| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229 |
- import { describe, expect, test } from "bun:test"
- import {
- buildConfigOptions,
- buildEffortSelectOption,
- buildModeSelectOption,
- buildModelSelectOption,
- formatCurrentModelId,
- formatVariantName,
- parseModelSelection,
- type ConfigOptionProvider,
- } from "@/acp/config-option"
- const providers: ConfigOptionProvider[] = [
- {
- id: "anthropic",
- name: "Anthropic",
- models: {
- "claude/sonnet-4": {
- id: "claude/sonnet-4",
- name: "Claude Sonnet 4",
- variants: {
- default: {},
- high: {},
- "very-high": {},
- },
- },
- "claude-haiku": {
- id: "claude-haiku",
- name: "Claude Haiku",
- },
- },
- },
- {
- id: "openai",
- name: "OpenAI",
- models: {
- "gpt-5": {
- id: "gpt-5",
- name: "GPT-5",
- variants: {
- minimal: {},
- low: {},
- },
- },
- },
- },
- ]
- describe("acp config options", () => {
- test("builds the model select option with ACP verifier category", () => {
- expect(
- buildModelSelectOption({
- providers,
- currentModel: { providerID: "anthropic", modelID: "claude/sonnet-4" },
- currentVariant: "high",
- }),
- ).toEqual({
- id: "model",
- name: "Model",
- category: "model",
- type: "select",
- currentValue: "anthropic/claude/sonnet-4",
- options: [
- { value: "anthropic/claude-haiku", name: "Anthropic/Claude Haiku" },
- { value: "anthropic/claude/sonnet-4", name: "Anthropic/Claude Sonnet 4" },
- { value: "openai/gpt-5", name: "OpenAI/GPT-5" },
- ],
- })
- })
- test("includes variant ids in the model option only when requested", () => {
- const option = buildModelSelectOption({
- providers,
- currentModel: { providerID: "anthropic", modelID: "claude/sonnet-4" },
- currentVariant: "high",
- includeVariants: true,
- })
- expect(option.currentValue).toBe("anthropic/claude/sonnet-4/high")
- if (option.type !== "select") throw new Error("expected select option")
- expect(option.options).toContainEqual({
- value: "anthropic/claude/sonnet-4/high",
- name: "Anthropic/Claude Sonnet 4 (High)",
- })
- expect(option.options).not.toContainEqual({
- value: "anthropic/claude/sonnet-4/default",
- name: "Anthropic/Claude Sonnet 4 (Default)",
- })
- })
- test("builds effort option from variants and falls back to default when current variant is invalid", () => {
- expect(buildEffortSelectOption({ variants: ["low", "default", "high"], currentVariant: "missing" })).toEqual({
- id: "effort",
- name: "Effort",
- description: "Available effort levels for this model",
- category: "thought_level",
- type: "select",
- currentValue: "default",
- options: [
- { value: "low", name: "Low" },
- { value: "default", name: "Default" },
- { value: "high", name: "High" },
- ],
- })
- })
- test("effort fallback uses the first variant when default is absent", () => {
- expect(buildEffortSelectOption({ variants: ["minimal", "low"], currentVariant: "missing" })?.currentValue).toBe(
- "minimal",
- )
- })
- test("omits effort option when there are no variants", () => {
- expect(buildEffortSelectOption({ variants: [] })).toBeUndefined()
- })
- test("builds the mode select option with descriptions when present", () => {
- expect(
- buildModeSelectOption({
- currentModeId: "build",
- modes: [
- { id: "build", name: "Build", description: "Make code changes" },
- { id: "plan", name: "Plan" },
- ],
- }),
- ).toEqual({
- id: "mode",
- name: "Session Mode",
- category: "mode",
- type: "select",
- currentValue: "build",
- options: [
- { value: "build", name: "Build", description: "Make code changes" },
- { value: "plan", name: "Plan" },
- ],
- })
- })
- test("builds full config options with model, effort, and mode in stable order", () => {
- const options = buildConfigOptions({
- providers,
- currentModel: { providerID: "anthropic", modelID: "claude/sonnet-4" },
- currentVariant: "very-high",
- modes: [
- { id: "build", name: "Build" },
- { id: "plan", name: "Plan" },
- ],
- currentModeId: "plan",
- })
- expect(options.map((option) => option.id)).toEqual(["model", "effort", "mode"])
- expect(options.map((option) => option.category)).toEqual(["model", "thought_level", "mode"])
- expect(options[1]?.currentValue).toBe("very-high")
- })
- test("full config options omit effort for models without variants", () => {
- expect(
- buildConfigOptions({
- providers,
- currentModel: { providerID: "anthropic", modelID: "claude-haiku" },
- }).map((option) => option.id),
- ).toEqual(["model"])
- })
- test("parses provider/model selections", () => {
- expect(parseModelSelection("openai/gpt-5", providers)).toEqual({
- model: { providerID: "openai", modelID: "gpt-5" },
- })
- })
- test("parses provider/model/variant selections when the base model exposes that variant", () => {
- expect(parseModelSelection("openai/gpt-5/low", providers)).toEqual({
- model: { providerID: "openai", modelID: "gpt-5" },
- variant: "low",
- })
- })
- test("prefers exact slash-containing model ids before treating the tail as a variant", () => {
- expect(parseModelSelection("anthropic/claude/sonnet-4", providers)).toEqual({
- model: { providerID: "anthropic", modelID: "claude/sonnet-4" },
- })
- })
- test("parses trailing variants for slash-containing model ids", () => {
- expect(parseModelSelection("anthropic/claude/sonnet-4/high", providers)).toEqual({
- model: { providerID: "anthropic", modelID: "claude/sonnet-4" },
- variant: "high",
- })
- })
- test("keeps unknown trailing segments in the model id when they are not valid variants", () => {
- expect(parseModelSelection("anthropic/claude/sonnet-4/missing", providers)).toEqual({
- model: { providerID: "anthropic", modelID: "claude/sonnet-4/missing" },
- })
- })
- test("formats current model ids with and without selected variants", () => {
- expect(
- formatCurrentModelId({
- model: { providerID: "openai", modelID: "gpt-5" },
- variant: "low",
- variants: ["minimal", "low"],
- }),
- ).toBe("openai/gpt-5")
- expect(
- formatCurrentModelId({
- model: { providerID: "openai", modelID: "gpt-5" },
- variant: "low",
- variants: ["minimal", "low"],
- includeVariant: true,
- }),
- ).toBe("openai/gpt-5/low")
- })
- test("formats current model ids with variant fallback", () => {
- expect(
- formatCurrentModelId({
- model: { providerID: "anthropic", modelID: "claude/sonnet-4" },
- variant: "missing",
- variants: ["default", "high"],
- includeVariant: true,
- }),
- ).toBe("anthropic/claude/sonnet-4/default")
- })
- test("formats variant names for display", () => {
- expect(formatVariantName("very_high-effort")).toBe("Very High Effort")
- })
- })
|