model-resolver.test.ts

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: GPL-3.0-or-later
 4
 5import { describe, test, expect } from "bun:test";
 6import { resolveModel } from "../src/agent/model-resolver.js";
 7import type { RumiloConfig } from "../src/config/schema.js";
 8import { ConfigError } from "../src/util/errors.js";
 9
10// Minimal config stub for tests
11const stubConfig: RumiloConfig = {
12  defaults: { model: "test:m", cleanup: true },
13  web: { model: "test:m" },
14  repo: { model: "test:m", default_depth: 1, blob_limit: "5m" },
15  custom_models: {},
16};
17
18describe("resolveModel - colon handling (issue #5)", () => {
19  test("model string with multiple colons preserves segments after second colon", () => {
20    // e.g. "openrouter:google/gemini-2.5-pro:free" should parse as
21    // provider = "openrouter", modelName = "google/gemini-2.5-pro:free"
22    // This will throw from getModel (unknown provider) but the parsed modelName
23    // should contain the full string after the first colon.
24    // We test via custom: prefix where we can control resolution.
25    const config: RumiloConfig = {
26      ...stubConfig,
27      custom_models: {
28        "name:with:colons": {
29          id: "test-id",
30          name: "test",
31          api: "openai",
32          provider: "test",
33          base_url: "http://localhost",
34          reasoning: false,
35          input: ["text"],
36          cost: { input: 0, output: 0 },
37          context_window: 1000,
38          max_tokens: 500,
39        },
40      },
41    };
42    // "custom:name:with:colons" should split as provider="custom", modelName="name:with:colons"
43    const model = resolveModel("custom:name:with:colons", config);
44    expect(model.id).toBe("test-id");
45  });
46
47  test("simple provider:model still works", () => {
48    // This will call getModel which may throw for unknown providers,
49    // but at minimum the split should be correct. Test with custom.
50    const config: RumiloConfig = {
51      ...stubConfig,
52      custom_models: {
53        "simple": {
54          id: "simple-id",
55          name: "simple",
56          api: "openai",
57          provider: "test",
58          base_url: "http://localhost",
59          reasoning: false,
60          input: ["text"],
61          cost: { input: 0, output: 0 },
62          context_window: 1000,
63          max_tokens: 500,
64        },
65      },
66    };
67    const model = resolveModel("custom:simple", config);
68    expect(model.id).toBe("simple-id");
69  });
70
71  test("rejects model string without colon", () => {
72    expect(() => resolveModel("nocodelimiter", stubConfig)).toThrow(ConfigError);
73  });
74});