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