Files
openwork/apps/app/tests/automation-model-options.test.ts

190 lines
7.2 KiB
TypeScript

import { describe, expect, test } from "bun:test"
import type { DenOrgLlmProvider } from "../src/app/lib/den"
import {
automationModelOptions,
automationPickerOptions,
describeAutomationModel,
resolveProposalModel,
} from "../src/react-app/domains/automations/automation-model-options"
function provider(input: Partial<DenOrgLlmProvider> & Pick<DenOrgLlmProvider, "id" | "name" | "source">): DenOrgLlmProvider {
return {
providerId: input.id,
providerConfig: {},
models: [],
canManage: false,
createdAt: "2026-08-03T00:00:00.000Z",
updatedAt: "2026-08-03T00:00:00.000Z",
...input,
}
}
describe("Automation model options", () => {
test("always offers the normalized free starter model", () => {
expect(automationModelOptions([])).toEqual([{
providerId: "opencode",
modelId: "big-pickle",
providerName: "OpenCode Zen",
modelName: "Big Pickle",
accessKind: "free",
}])
})
test("removes the free starter model when desktop policy disables OpenCode Zen", () => {
expect(automationModelOptions([], { includeFreeStarter: false })).toEqual([])
})
test("expands the member's managed OpenWork aliases even when Den stores no model rows", () => {
const options = automationModelOptions([
provider({ id: "lpr_member_openwork", source: "openwork", name: "OpenWork Models" }),
])
expect(options.some((option) => option.providerId === "openwork" && option.modelId === "z-ai/glm-5.2")).toBe(true)
expect(options.some((option) => option.providerId === "lpr_member_openwork")).toBe(false)
})
test("keeps authorized custom providers on their concrete Den provider IDs", () => {
const options = automationModelOptions([
provider({
id: "lpr_team",
source: "custom",
name: "Team Provider",
models: [{ id: "team-model", name: "Team Model", config: {}, createdAt: "2026-08-03T00:00:00.000Z" }],
}),
])
expect(options).toContainEqual({
providerId: "lpr_team",
modelId: "team-model",
providerName: "Team Provider",
modelName: "Team Model",
accessKind: "authorized_custom",
})
})
test("labels a stored model for people, and falls back to raw identity when access is gone", () => {
const options = automationModelOptions([
provider({
id: "lpr_team",
source: "custom",
name: "Team Provider",
models: [{ id: "team-model", name: "Team Model", config: {}, createdAt: "2026-08-03T00:00:00.000Z" }],
}),
])
expect(describeAutomationModel({ providerId: "lpr_team", modelId: "team-model" }, options))
.toBe("Team Provider · Team Model")
expect(describeAutomationModel({ providerId: "lpr_team", modelId: "team-model", variant: "high" }, options))
.toBe("Team Provider · Team Model · high")
// A revoked model must stay inspectable rather than render as a blank.
expect(describeAutomationModel({ providerId: "lpr_gone", modelId: "vanished" }, options))
.toBe("lpr_gone/vanished")
})
test("offers the runtime's reasoning levels for the selected model only", () => {
const options = automationModelOptions([
provider({
id: "lpr_team",
source: "custom",
name: "Team Provider",
models: [{ id: "team-model", name: "Team Model", config: {}, createdAt: "2026-08-03T00:00:00.000Z" }],
}),
])
const catalog = {
lpr_team: {
"team-model": {
id: "team-model",
name: "Team Model",
variants: { low: {}, high: {} },
},
},
} as never
const picker = automationPickerOptions({
options,
catalog,
selected: { providerId: "lpr_team", modelId: "team-model", variant: "high" },
})
const selected = picker.find((option) => option.modelID === "team-model")
const free = picker.find((option) => option.modelID === "big-pickle")
expect(selected?.behaviorValue).toBe("high")
expect(selected?.behaviorOptions?.map((option) => option.value)).toContain("low")
expect(selected?.isFree).toBe(false)
// The free starter model is absent from the local catalog here, so it
// still lists — just without reasoning levels.
expect(free?.isFree).toBe(true)
expect(free?.behaviorOptions).toEqual([])
})
})
describe("Automation proposal model resolution", () => {
const customProvider = provider({
id: "lpr_abc",
providerId: "deepseek",
source: "custom",
name: "DeepSeek",
models: [{ id: "deepseek-v4-flash", name: "DeepSeek V4 Flash", config: {}, createdAt: null }],
})
test("defaults an omitted model to the free starter model", () => {
expect(resolveProposalModel(undefined, [])).toEqual({
model: { providerId: "opencode", modelId: "big-pickle", variant: null },
resolution: "default",
})
})
test("preserves exact custom, free, and managed model identities", () => {
const custom = { providerId: "lpr_abc", modelId: "deepseek-v4-flash", variant: "high" }
expect(resolveProposalModel(custom, [customProvider])).toEqual({ model: custom, resolution: "exact" })
const free = { providerId: "opencode", modelId: "big-pickle", variant: "low" }
expect(resolveProposalModel(free, [])).toEqual({ model: free, resolution: "exact" })
const managedProvider = provider({ id: "lpr_managed", source: "openwork", name: "OpenWork Models" })
const managedOption = automationModelOptions([managedProvider]).find((option) => option.accessKind === "openwork_managed")
expect(managedOption).toBeDefined()
if (!managedOption) throw new Error("Expected an enabled OpenWork managed model")
const managed = { providerId: managedOption.providerId, modelId: managedOption.modelId, variant: "high" }
expect(resolveProposalModel(managed, [managedProvider])).toEqual({ model: managed, resolution: "exact" })
})
test("maps an upstream provider key to the first matching concrete Den provider", () => {
const first = provider({ ...customProvider, id: "lpr_first" })
const second = provider({ ...customProvider, id: "lpr_second" })
expect(resolveProposalModel(
{ providerId: "deepseek", modelId: "deepseek-v4-flash", variant: "high" },
[first, second],
)).toEqual({
model: { providerId: "lpr_first", modelId: "deepseek-v4-flash", variant: "high" },
resolution: "mapped",
})
})
test("does not map through OpenWork provider records", () => {
const managed = provider({
...customProvider,
id: "lpr_managed",
source: "openwork",
})
expect(resolveProposalModel(
{ providerId: "deepseek", modelId: "deepseek-v4-flash" },
[managed],
)).toEqual({
model: { providerId: "opencode", modelId: "big-pickle", variant: null },
resolution: "fallback",
})
})
test("falls back when the provider or model is unavailable", () => {
const fallback = {
model: { providerId: "opencode", modelId: "big-pickle", variant: null },
resolution: "fallback",
}
expect(resolveProposalModel({ providerId: "unknown", modelId: "missing", variant: "high" }, [customProvider]))
.toEqual(fallback)
expect(resolveProposalModel({ providerId: "deepseek", modelId: "missing", variant: "high" }, [customProvider]))
.toEqual(fallback)
})
})