Download packages/sdk-next/test/embedded.test.ts from SaylorTwift/opencode: direct link, hf CLI and curl.
- Browser
- Download file 9.46 kB
-
https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/sdk-next/test/embedded.test.ts
- Command line
-
hf download hf://SaylorTwift/opencode/packages/sdk-next/test/embedded.test.ts
-
curl -L -o embedded.test.ts https://huggingface.co/SaylorTwift/opencode/resolve/main/packages/sdk-next/test/embedded.test.ts
9.46 kB
| import { expect, test } from "bun:test" | |
| import { mkdtemp, rm } from "node:fs/promises" | |
| import { tmpdir } from "node:os" | |
| import { join } from "node:path" | |
| import { Flag } from "@opencode-ai/core/flag/flag" | |
| import { Deferred, Effect, Latch, Option, Schema, Stream } from "effect" | |
| import type { OpenCodeEvent } from "../src" | |
| test("embedded client uses the real router and handlers", async () => { | |
| const directory = await mkdtemp(join(tmpdir(), "opencode-embedded-")) | |
| const database = Flag.OPENCODE_DB | |
| Flag.OPENCODE_DB = join(directory, "opencode.sqlite") | |
| const { AbsolutePath, Agent, Location, Model, OpenCode, Prompt, Provider, Session, Tool } = await import("../src") | |
| const sessionID = Session.ID.make(`ses_embedded_${crypto.randomUUID()}`) | |
| const model = Model.Ref.make({ id: Model.ID.make("embedded"), providerID: Provider.ID.make("test") }) | |
| try { | |
| const program = Effect.gen(function* () { | |
| const opencode = yield* OpenCode.create() | |
| yield* opencode.tools.register({ | |
| embedded_tool: Tool.make({ | |
| description: "Embedded test tool", | |
| input: Schema.Struct({}), | |
| output: Schema.Struct({ ok: Schema.Boolean }), | |
| execute: () => Effect.succeed({ ok: true }), | |
| }), | |
| }) | |
| const created = yield* opencode.sessions.create({ | |
| id: sessionID, | |
| agent: Agent.ID.make("build"), | |
| location: Location.Ref.make({ directory: AbsolutePath.make(directory) }), | |
| }) | |
| yield* opencode.sessions.switchModel({ sessionID, model }) | |
| const selected = yield* opencode.sessions.get({ sessionID }) | |
| const page = yield* opencode.sessions.list({ directory: AbsolutePath.make(directory) }) | |
| const active = yield* opencode.sessions.active() | |
| const admitted = yield* opencode.sessions.prompt({ | |
| sessionID, | |
| prompt: Prompt.make({ text: "Do not run" }), | |
| resume: false, | |
| }) | |
| const context = yield* opencode.sessions.context({ sessionID }) | |
| const wake = yield* opencode.sessions.prompt({ | |
| sessionID, | |
| prompt: Prompt.make({ text: "Promote this input" }), | |
| }) | |
| const prompted = yield* opencode.sessions.events({ sessionID }).pipe( | |
| Stream.filter((event) => event.type === "session.next.prompted" && event.data.messageID === wake.id), | |
| Stream.runHead, | |
| Effect.timeout("10 seconds"), | |
| Effect.map(Option.getOrThrow), | |
| ) | |
| const wakeContext = yield* opencode.sessions.context({ sessionID }) | |
| const event = yield* opencode.sessions | |
| .events({ sessionID }) | |
| .pipe(Stream.take(1), Stream.runHead, Effect.map(Option.getOrUndefined)) | |
| const modelMessage = Option.fromNullishOr(context.find((message) => message.type === "model-switched")).pipe( | |
| Option.getOrThrow, | |
| ) | |
| const message = yield* opencode.sessions.message({ sessionID, messageID: modelMessage.id }) | |
| yield* opencode.sessions.interrupt({ sessionID }) | |
| const other = yield* opencode.sessions.create({ | |
| location: Location.Ref.make({ directory: AbsolutePath.make(directory) }), | |
| }) | |
| const missingSessionID = Session.ID.make(`ses_missing_${crypto.randomUUID()}`) | |
| const missing = yield* Effect.all( | |
| [ | |
| opencode.sessions.events({ sessionID: missingSessionID }).pipe(Stream.runHead, Effect.flip), | |
| opencode.sessions.interrupt({ sessionID: missingSessionID }).pipe(Effect.flip), | |
| opencode.sessions.message({ sessionID: missingSessionID, messageID: modelMessage.id }).pipe(Effect.flip), | |
| ], | |
| { concurrency: "unbounded" }, | |
| ) | |
| const missingMessage = yield* Effect.flip( | |
| opencode.sessions.message({ | |
| sessionID: other.id, | |
| messageID: modelMessage.id, | |
| }), | |
| ) | |
| expect(created.id).toBe(sessionID) | |
| expect(selected.model?.id).toBe(model.id) | |
| expect(selected.model?.providerID).toBe(model.providerID) | |
| expect(page.data.some((session) => session.id === sessionID)).toBe(true) | |
| expect(active).toEqual({}) | |
| expect(admitted.sessionID).toBe(sessionID) | |
| expect(prompted.type).toBe("session.next.prompted") | |
| expect(wakeContext).toContainEqual(expect.objectContaining({ id: wake.id, type: "user" })) | |
| expect(context.some((message) => message.type === "model-switched")).toBe(true) | |
| expect(event).toMatchObject({ type: "session.next.model.switched", durable: { seq: 1 } }) | |
| expect(message).toEqual(modelMessage) | |
| expect(missing.map((error) => error._tag)).toEqual([ | |
| "SessionNotFoundError", | |
| "SessionNotFoundError", | |
| "SessionNotFoundError", | |
| ]) | |
| expect(missingMessage._tag).toBe("MessageNotFoundError") | |
| }) | |
| await Effect.runPromise(Effect.scoped(program)) | |
| } finally { | |
| Flag.OPENCODE_DB = database | |
| await rm(directory, { recursive: true, force: true }) | |
| } | |
| }) | |
| test("Location-owned runner events reach the ready global client", async () => { | |
| const directory = await mkdtemp(join(tmpdir(), "opencode-embedded-events-")) | |
| const database = Flag.OPENCODE_DB | |
| Flag.OPENCODE_DB = join(directory, "opencode.sqlite") | |
| const { AbsolutePath, Location, OpenCode, Prompt, Session } = await import("../src") | |
| const sessionID = Session.ID.make(`ses_embedded_${crypto.randomUUID()}`) | |
| try { | |
| const program = Effect.gen(function* () { | |
| const opencode = yield* OpenCode.create() | |
| const connected = yield* Latch.make(false) | |
| const prompted = yield* Deferred.make<OpenCodeEvent>() | |
| yield* opencode.events.subscribe().pipe( | |
| Stream.runForEach((event) => | |
| event.type === "server.connected" | |
| ? connected.open | |
| : event.type === "session.next.prompted" && event.data.sessionID === sessionID | |
| ? Deferred.succeed(prompted, event).pipe(Effect.asVoid) | |
| : Effect.void, | |
| ), | |
| Effect.forkScoped, | |
| ) | |
| yield* connected.await | |
| yield* opencode.sessions.create({ | |
| id: sessionID, | |
| location: Location.Ref.make({ directory: AbsolutePath.make(directory) }), | |
| }) | |
| yield* opencode.sessions.prompt({ sessionID, prompt: Prompt.make({ text: "Observe this input" }) }) | |
| const event = yield* Deferred.await(prompted).pipe(Effect.timeout("4 seconds")) | |
| expect(event.durable).toEqual(expect.objectContaining({ aggregateID: sessionID, seq: expect.any(Number) })) | |
| }) | |
| await Effect.runPromise(Effect.scoped(program)) | |
| } finally { | |
| Flag.OPENCODE_DB = database | |
| await rm(directory, { recursive: true, force: true }) | |
| } | |
| }, 10_000) | |
| test("independent embedded hosts do not share live notifications", async () => { | |
| const directory = await mkdtemp(join(tmpdir(), "opencode-embedded-hosts-")) | |
| const database = Flag.OPENCODE_DB | |
| Flag.OPENCODE_DB = join(directory, "opencode.sqlite") | |
| const { AbsolutePath, Agent, Location, OpenCode, Session } = await import("../src") | |
| const sessionID = Session.ID.make(`ses_embedded_${crypto.randomUUID()}`) | |
| try { | |
| const program = Effect.gen(function* () { | |
| const first = yield* OpenCode.create() | |
| const second = yield* OpenCode.create() | |
| const firstReady = yield* Latch.make(false) | |
| const secondReady = yield* Latch.make(false) | |
| const firstEvent = yield* Latch.make(false) | |
| const secondEvent = yield* Latch.make(false) | |
| const observe = (ready: Latch.Latch, event: Latch.Latch) => | |
| Stream.runForEach((notification: OpenCodeEvent) => | |
| notification.type === "server.connected" | |
| ? ready.open | |
| : notification.type === "session.next.agent.switched" && notification.data.sessionID === sessionID | |
| ? event.open | |
| : Effect.void, | |
| ) | |
| yield* first.events.subscribe().pipe(observe(firstReady, firstEvent), Effect.forkScoped) | |
| yield* second.events.subscribe().pipe(observe(secondReady, secondEvent), Effect.forkScoped) | |
| yield* Effect.all([firstReady.await, secondReady.await], { discard: true }) | |
| yield* first.sessions.create({ | |
| id: sessionID, | |
| location: Location.Ref.make({ directory: AbsolutePath.make(directory) }), | |
| }) | |
| yield* first.sessions.switchAgent({ sessionID, agent: Agent.ID.make("plan") }) | |
| yield* firstEvent.await.pipe(Effect.timeout("2 seconds")) | |
| expect(Option.isNone(yield* secondEvent.await.pipe(Effect.timeoutOption("100 millis")))).toBe(true) | |
| }) | |
| await Effect.runPromise(Effect.scoped(program)) | |
| } finally { | |
| Flag.OPENCODE_DB = database | |
| await rm(directory, { recursive: true, force: true }) | |
| } | |
| }, 10_000) | |
| test("embedded client is available as a Layer service", async () => { | |
| const directory = await mkdtemp(join(tmpdir(), "opencode-embedded-layer-")) | |
| const database = Flag.OPENCODE_DB | |
| Flag.OPENCODE_DB = join(directory, "opencode.sqlite") | |
| const { AbsolutePath, Location, OpenCode, Session } = await import("../src") | |
| const sessionID = Session.ID.make(`ses_embedded_${crypto.randomUUID()}`) | |
| try { | |
| const created = await Effect.runPromise( | |
| Effect.gen(function* () { | |
| const opencode = yield* OpenCode.Service | |
| return yield* opencode.sessions.create({ | |
| id: sessionID, | |
| location: Location.Ref.make({ directory: AbsolutePath.make(directory) }), | |
| }) | |
| }).pipe(Effect.provide(OpenCode.layer), Effect.scoped), | |
| ) | |
| expect(created.id).toBe(sessionID) | |
| } finally { | |
| Flag.OPENCODE_DB = database | |
| await rm(directory, { recursive: true, force: true }) | |
| } | |
| }) | |