mirror of
https://github.com/anomalyco/opencode.git
synced 2026-10-25 09:10:04 +00:00
90 lines
4.5 KiB
TypeScript
90 lines
4.5 KiB
TypeScript
import { expect } from "bun:test"
|
|
import { DateTime, Effect, Layer } from "effect"
|
|
import { AppNodeBuilder } from "@opencode/core/effect/app-node-builder"
|
|
import { LayerNode } from "@opencode/util/effect/layer-node"
|
|
import { Location } from "@opencode/core/location"
|
|
import { Model } from "@opencode/core/model"
|
|
import { ModelResolver } from "@opencode/core/model-resolver"
|
|
import { Project } from "@opencode/core/project"
|
|
import { Provider } from "@opencode/core/provider"
|
|
import { AbsolutePath } from "@opencode/core/schema"
|
|
import { Session } from "@opencode/core/session"
|
|
import { SessionRunnerModel } from "@opencode/core/session/runner/model"
|
|
import { Money } from "@opencode/schema/money"
|
|
import { withEnv } from "./fixture/env"
|
|
import { location } from "./fixture/location"
|
|
import { it } from "./lib/effect"
|
|
|
|
const ref = location({ directory: AbsolutePath.make("test") })
|
|
const layer = AppNodeBuilder.build(
|
|
LayerNode.group([Provider.node, Model.node, ModelResolver.node, SessionRunnerModel.node]),
|
|
[Location.node.replace(Layer.succeed(Location.Service, Location.Service.of(ref)))],
|
|
)
|
|
const free = Model.ID.make("big-pickle")
|
|
const paid = Model.ID.make("paid")
|
|
const local = Model.ID.make("local")
|
|
const other = Provider.ID.make("other")
|
|
|
|
for (const flag of [undefined, "0", "1", "true"]) {
|
|
for (const providerID of [Provider.ID.opencode, Provider.ID.make("opencode-go")])
|
|
it.effect(`${providerID} catalog with OPENCODE_DISABLE_FREE_MODELS=${flag}`, () =>
|
|
withEnv({ OPENCODE_DISABLE_FREE_MODELS: flag }, () =>
|
|
Effect.gen(function* () {
|
|
const providers = yield* Provider.Service
|
|
const models = yield* Model.Service
|
|
const runner = yield* SessionRunnerModel.Service
|
|
const resolver = yield* ModelResolver.Service
|
|
yield* providers.transform((editor) => {
|
|
editor.update(providerID, () => {})
|
|
editor.models.update(providerID, free, (model) => {
|
|
model.time.released = 3000
|
|
model.family = Model.Family.make("gpt-luna")
|
|
model.capabilities = { ...model.capabilities, input: ["text"], output: ["text"] }
|
|
})
|
|
editor.models.update(providerID, paid, (model) => {
|
|
model.time.released = 2000
|
|
model.cost = [
|
|
{
|
|
input: Money.USDPerMillionTokens.make(1),
|
|
output: Money.USDPerMillionTokens.zero,
|
|
cache: { read: Money.USDPerMillionTokens.zero, write: Money.USDPerMillionTokens.zero },
|
|
},
|
|
]
|
|
})
|
|
editor.update(other, () => {})
|
|
editor.models.update(other, local, () => {})
|
|
})
|
|
yield* models.transform((editor) => editor.default.set(providerID, free))
|
|
const disabled = flag === "1" || flag === "true"
|
|
expect((yield* models.all()).map((model) => model.id)).toEqual(disabled ? [paid, local] : [free, paid, local])
|
|
expect(yield* models.available()).toEqual(yield* models.all())
|
|
expect((yield* models.default())?.id).toBe(disabled ? paid : free)
|
|
expect((yield* models.get(providerID, free))?.id).toBe(disabled ? undefined : free)
|
|
expect((yield* models.small(providerID))?.id).toBe(disabled ? undefined : free)
|
|
if (!disabled) return
|
|
const session = Session.Info.make({
|
|
id: Session.ID.make("ses_free_model"),
|
|
projectID: Project.ID.global,
|
|
title: "test",
|
|
model: { id: free, providerID },
|
|
cost: Money.USD.zero,
|
|
tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
|
|
time: { created: DateTime.makeUnsafe(0), updated: DateTime.makeUnsafe(0) },
|
|
location: ref,
|
|
})
|
|
const failure = yield* runner.resolve(session, models.available).pipe(Effect.flip)
|
|
expect(failure.message).toBe(`Model unavailable: ${providerID}/big-pickle`)
|
|
expect(yield* resolver.resolve(Model.Ref.make({ providerID, id: free }))).toBeUndefined()
|
|
// Later transforms cannot restore a free model, even when all paid models are removed.
|
|
yield* models.transform((editor) => {
|
|
editor.update(providerID, free, (model) => {
|
|
model.enabled = true
|
|
})
|
|
editor.remove(providerID, paid)
|
|
})
|
|
expect((yield* models.default())?.providerID).toBe(other)
|
|
expect(yield* models.get(providerID, free)).toBeUndefined()
|
|
}).pipe(Effect.provide(layer)),
|
|
),
|
|
)
|
|
}
|