mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-24 06:33:01 -04:00
120 lines
4.4 KiB
TypeScript
120 lines
4.4 KiB
TypeScript
import fs from "node:fs/promises"
|
|
import path from "node:path"
|
|
import { expect } from "bun:test"
|
|
import { Effect } from "effect"
|
|
import { HttpServer } from "effect/unstable/http"
|
|
import { tmpdir } from "../../core/test/fixture/tmpdir"
|
|
import { it } from "../../core/test/lib/effect"
|
|
import { ServerProcess } from "../src/process"
|
|
|
|
it.live("resolves configured agent models after plugin initialization", () =>
|
|
Effect.acquireUseRelease(
|
|
Effect.promise(() => tmpdir("opencode-session-endpoint-")),
|
|
(tmp) =>
|
|
Effect.gen(function* () {
|
|
yield* Effect.promise(() =>
|
|
fs.writeFile(
|
|
path.join(tmp.path, "opencode.json"),
|
|
JSON.stringify({
|
|
agents: {
|
|
modelprobe: {
|
|
description: "Model resolution probe",
|
|
mode: "primary",
|
|
model: "opencode/nemotron-3.5-lightning-free",
|
|
},
|
|
plain: { description: "No configured model", mode: "primary" },
|
|
},
|
|
}),
|
|
),
|
|
)
|
|
const server = yield* ServerProcess.start<never, never>({
|
|
hostname: "127.0.0.1",
|
|
port: 0,
|
|
password: "secret",
|
|
app: { version: "test-version" },
|
|
database: { path: ":memory:" },
|
|
config: { directory: tmp.path },
|
|
fs: { filewatcher: false },
|
|
})
|
|
const base = HttpServer.formatAddress(server.address)
|
|
const created = yield* request(base, "/api/session", {
|
|
agent: "modelprobe",
|
|
location: { directory: tmp.path },
|
|
})
|
|
if (!isRecord(created) || !isRecord(created["data"])) throw new Error("Expected a created session")
|
|
expect(created["data"]["model"]).toBeUndefined()
|
|
const sessionID = created["data"]["id"]
|
|
if (typeof sessionID !== "string") throw new Error("Expected a Session ID")
|
|
|
|
expect(
|
|
yield* request(base, `/api/session/${sessionID}/selection`, {
|
|
agent: "modelprobe",
|
|
model: { type: "configured" },
|
|
}),
|
|
).toBeUndefined()
|
|
const configured = yield* get(base, `/api/session/${sessionID}`)
|
|
if (!isRecord(configured) || !isRecord(configured["data"])) throw new Error("Expected a Session")
|
|
expect(configured["data"]).toMatchObject({
|
|
agent: "modelprobe",
|
|
model: {
|
|
providerID: "opencode",
|
|
id: "nemotron-3.5-lightning-free",
|
|
variant: "default",
|
|
},
|
|
})
|
|
|
|
expect(
|
|
yield* request(base, `/api/session/${sessionID}/selection`, {
|
|
agent: "plain",
|
|
model: { type: "configured" },
|
|
}),
|
|
).toBeUndefined()
|
|
const preserved = yield* get(base, `/api/session/${sessionID}`)
|
|
if (!isRecord(preserved) || !isRecord(preserved["data"])) throw new Error("Expected a Session")
|
|
expect(preserved["data"]).toMatchObject({ agent: "plain", model: configured["data"]["model"] })
|
|
|
|
expect(
|
|
yield* request(base, `/api/session/${sessionID}/selection`, {
|
|
agent: "missing",
|
|
model: { type: "configured" },
|
|
}),
|
|
).toBeUndefined()
|
|
const missing = yield* get(base, `/api/session/${sessionID}`)
|
|
if (!isRecord(missing) || !isRecord(missing["data"])) throw new Error("Expected a Session")
|
|
expect(missing["data"]).toMatchObject({ agent: "missing", model: configured["data"]["model"] })
|
|
}),
|
|
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
|
),
|
|
)
|
|
|
|
function request(base: string, pathname: string, body: unknown) {
|
|
return Effect.promise(() =>
|
|
fetch(new URL(pathname, base), {
|
|
method: "POST",
|
|
headers: {
|
|
authorization: `Basic ${btoa("opencode:secret")}`,
|
|
"content-type": "application/json",
|
|
},
|
|
body: JSON.stringify(body),
|
|
}).then(async (response) => {
|
|
expect(response.status).toBe(pathname === "/api/session" ? 200 : 204)
|
|
return response.status === 204 ? undefined : response.json()
|
|
}),
|
|
)
|
|
}
|
|
|
|
function get(base: string, pathname: string) {
|
|
return Effect.promise(() =>
|
|
fetch(new URL(pathname, base), {
|
|
headers: { authorization: `Basic ${btoa("opencode:secret")}` },
|
|
}).then((response) => {
|
|
expect(response.status).toBe(200)
|
|
return response.json()
|
|
}),
|
|
)
|
|
}
|
|
|
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
}
|