Files
clawdbot/src/agents/model-selection.test.ts
Senol Dogan 7253bf398d feat: audit fixes and documentation improvements (#1762)
* feat: audit fixes and documentation improvements

- Refactored model selection to drop legacy fallback and add warning
- Improved heartbeat content validation
- Added Skill Creation guide
- Updated CONTRIBUTING.md with roadmap

* style: fix formatting in model-selection.ts

* style: fix formatting and improve model selection logic with tests
2026-01-25 12:54:48 +00:00

140 lines
4.4 KiB
TypeScript

import { describe, it, expect, vi } from "vitest";
import {
parseModelRef,
resolveModelRefFromString,
resolveConfiguredModelRef,
buildModelAliasIndex,
normalizeProviderId,
modelKey,
} from "./model-selection.js";
import type { ClawdbotConfig } from "../config/config.js";
describe("model-selection", () => {
describe("normalizeProviderId", () => {
it("should normalize provider names", () => {
expect(normalizeProviderId("Anthropic")).toBe("anthropic");
expect(normalizeProviderId("Z.ai")).toBe("zai");
expect(normalizeProviderId("z-ai")).toBe("zai");
expect(normalizeProviderId("OpenCode-Zen")).toBe("opencode");
expect(normalizeProviderId("qwen")).toBe("qwen-portal");
});
});
describe("parseModelRef", () => {
it("should parse full model refs", () => {
expect(parseModelRef("anthropic/claude-3-5-sonnet", "openai")).toEqual({
provider: "anthropic",
model: "claude-3-5-sonnet",
});
});
it("should use default provider if none specified", () => {
expect(parseModelRef("claude-3-5-sonnet", "anthropic")).toEqual({
provider: "anthropic",
model: "claude-3-5-sonnet",
});
});
it("should return null for empty strings", () => {
expect(parseModelRef("", "anthropic")).toBeNull();
expect(parseModelRef(" ", "anthropic")).toBeNull();
});
it("should handle invalid slash usage", () => {
expect(parseModelRef("/", "anthropic")).toBeNull();
expect(parseModelRef("anthropic/", "anthropic")).toBeNull();
expect(parseModelRef("/model", "anthropic")).toBeNull();
});
});
describe("buildModelAliasIndex", () => {
it("should build alias index from config", () => {
const cfg: Partial<ClawdbotConfig> = {
agents: {
defaults: {
models: {
"anthropic/claude-3-5-sonnet": { alias: "fast" },
"openai/gpt-4o": { alias: "smart" },
},
},
},
};
const index = buildModelAliasIndex({
cfg: cfg as ClawdbotConfig,
defaultProvider: "anthropic",
});
expect(index.byAlias.get("fast")?.ref).toEqual({
provider: "anthropic",
model: "claude-3-5-sonnet",
});
expect(index.byAlias.get("smart")?.ref).toEqual({ provider: "openai", model: "gpt-4o" });
expect(index.byKey.get(modelKey("anthropic", "claude-3-5-sonnet"))).toEqual(["fast"]);
});
});
describe("resolveModelRefFromString", () => {
it("should resolve from string with alias", () => {
const index = {
byAlias: new Map([
["fast", { alias: "fast", ref: { provider: "anthropic", model: "sonnet" } }],
]),
byKey: new Map(),
};
const resolved = resolveModelRefFromString({
raw: "fast",
defaultProvider: "openai",
aliasIndex: index,
});
expect(resolved?.ref).toEqual({ provider: "anthropic", model: "sonnet" });
expect(resolved?.alias).toBe("fast");
});
it("should resolve direct ref if no alias match", () => {
const resolved = resolveModelRefFromString({
raw: "openai/gpt-4",
defaultProvider: "anthropic",
});
expect(resolved?.ref).toEqual({ provider: "openai", model: "gpt-4" });
});
});
describe("resolveConfiguredModelRef", () => {
it("should fall back to anthropic and warn if provider is missing for non-alias", () => {
const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {});
const cfg: Partial<ClawdbotConfig> = {
agents: {
defaults: {
model: "claude-3-5-sonnet",
},
},
};
const result = resolveConfiguredModelRef({
cfg: cfg as ClawdbotConfig,
defaultProvider: "google",
defaultModel: "gemini-pro",
});
expect(result).toEqual({ provider: "anthropic", model: "claude-3-5-sonnet" });
expect(warnSpy).toHaveBeenCalledWith(
expect.stringContaining('Falling back to "anthropic/claude-3-5-sonnet"'),
);
warnSpy.mockRestore();
});
it("should use default provider/model if config is empty", () => {
const cfg: Partial<ClawdbotConfig> = {};
const result = resolveConfiguredModelRef({
cfg: cfg as ClawdbotConfig,
defaultProvider: "openai",
defaultModel: "gpt-4",
});
expect(result).toEqual({ provider: "openai", model: "gpt-4" });
});
});
});