Merged via /review-pr -> /prepare-pr -> /merge-pr. Prepared head SHA: f5a7e1a38574593838a7cd62ab9f1488f2da461e Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com> Reviewed-by: @gumadeiras
207 lines
7.1 KiB
TypeScript
207 lines
7.1 KiB
TypeScript
import { mkdtempSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { describe, expect, it } from "vitest";
|
|
import { resolveApiKeyForProvider, resolveEnvApiKey } from "../agents/model-auth.js";
|
|
import type { OpenClawConfig } from "../config/config.js";
|
|
import { resolveAgentModelPrimaryValue } from "../config/model-input.js";
|
|
import { captureEnv } from "../test-utils/env.js";
|
|
import {
|
|
applyKilocodeProviderConfig,
|
|
applyKilocodeConfig,
|
|
KILOCODE_BASE_URL,
|
|
} from "./onboard-auth.config-core.js";
|
|
import { KILOCODE_DEFAULT_MODEL_REF } from "./onboard-auth.credentials.js";
|
|
import {
|
|
buildKilocodeModelDefinition,
|
|
KILOCODE_DEFAULT_MODEL_ID,
|
|
KILOCODE_DEFAULT_CONTEXT_WINDOW,
|
|
KILOCODE_DEFAULT_MAX_TOKENS,
|
|
KILOCODE_DEFAULT_COST,
|
|
} from "./onboard-auth.models.js";
|
|
|
|
const emptyCfg: OpenClawConfig = {};
|
|
const KILOCODE_MODEL_IDS = [
|
|
"anthropic/claude-opus-4.6",
|
|
"z-ai/glm-5:free",
|
|
"minimax/minimax-m2.5:free",
|
|
"anthropic/claude-sonnet-4.5",
|
|
"openai/gpt-5.2",
|
|
"google/gemini-3-pro-preview",
|
|
"google/gemini-3-flash-preview",
|
|
"x-ai/grok-code-fast-1",
|
|
"moonshotai/kimi-k2.5",
|
|
];
|
|
|
|
describe("Kilo Gateway provider config", () => {
|
|
describe("constants", () => {
|
|
it("KILOCODE_BASE_URL points to kilo openrouter endpoint", () => {
|
|
expect(KILOCODE_BASE_URL).toBe("https://api.kilo.ai/api/gateway/");
|
|
});
|
|
|
|
it("KILOCODE_DEFAULT_MODEL_REF includes provider prefix", () => {
|
|
expect(KILOCODE_DEFAULT_MODEL_REF).toBe("kilocode/anthropic/claude-opus-4.6");
|
|
});
|
|
|
|
it("KILOCODE_DEFAULT_MODEL_ID is anthropic/claude-opus-4.6", () => {
|
|
expect(KILOCODE_DEFAULT_MODEL_ID).toBe("anthropic/claude-opus-4.6");
|
|
});
|
|
});
|
|
|
|
describe("buildKilocodeModelDefinition", () => {
|
|
it("returns correct model shape", () => {
|
|
const model = buildKilocodeModelDefinition();
|
|
expect(model.id).toBe(KILOCODE_DEFAULT_MODEL_ID);
|
|
expect(model.name).toBe("Claude Opus 4.6");
|
|
expect(model.reasoning).toBe(true);
|
|
expect(model.input).toEqual(["text", "image"]);
|
|
expect(model.contextWindow).toBe(KILOCODE_DEFAULT_CONTEXT_WINDOW);
|
|
expect(model.maxTokens).toBe(KILOCODE_DEFAULT_MAX_TOKENS);
|
|
expect(model.cost).toEqual(KILOCODE_DEFAULT_COST);
|
|
});
|
|
});
|
|
|
|
describe("applyKilocodeProviderConfig", () => {
|
|
it("registers kilocode provider with correct baseUrl and api", () => {
|
|
const result = applyKilocodeProviderConfig(emptyCfg);
|
|
const provider = result.models?.providers?.kilocode;
|
|
expect(provider).toBeDefined();
|
|
expect(provider?.baseUrl).toBe(KILOCODE_BASE_URL);
|
|
expect(provider?.api).toBe("openai-completions");
|
|
});
|
|
|
|
it("includes the default model in the provider model list", () => {
|
|
const result = applyKilocodeProviderConfig(emptyCfg);
|
|
const provider = result.models?.providers?.kilocode;
|
|
const models = provider?.models;
|
|
expect(Array.isArray(models)).toBe(true);
|
|
const modelIds = models?.map((m) => m.id) ?? [];
|
|
expect(modelIds).toContain(KILOCODE_DEFAULT_MODEL_ID);
|
|
});
|
|
|
|
it("surfaces the full Kilo model catalog", () => {
|
|
const result = applyKilocodeProviderConfig(emptyCfg);
|
|
const provider = result.models?.providers?.kilocode;
|
|
const modelIds = provider?.models?.map((m) => m.id) ?? [];
|
|
for (const modelId of KILOCODE_MODEL_IDS) {
|
|
expect(modelIds).toContain(modelId);
|
|
}
|
|
});
|
|
|
|
it("appends missing catalog models to existing Kilo provider config", () => {
|
|
const result = applyKilocodeProviderConfig({
|
|
models: {
|
|
providers: {
|
|
kilocode: {
|
|
baseUrl: KILOCODE_BASE_URL,
|
|
api: "openai-completions",
|
|
models: [buildKilocodeModelDefinition()],
|
|
},
|
|
},
|
|
},
|
|
});
|
|
const modelIds = result.models?.providers?.kilocode?.models?.map((m) => m.id) ?? [];
|
|
for (const modelId of KILOCODE_MODEL_IDS) {
|
|
expect(modelIds).toContain(modelId);
|
|
}
|
|
});
|
|
|
|
it("sets Kilo Gateway alias in agent default models", () => {
|
|
const result = applyKilocodeProviderConfig(emptyCfg);
|
|
const agentModel = result.agents?.defaults?.models?.[KILOCODE_DEFAULT_MODEL_REF];
|
|
expect(agentModel).toBeDefined();
|
|
expect(agentModel?.alias).toBe("Kilo Gateway");
|
|
});
|
|
|
|
it("preserves existing alias if already set", () => {
|
|
const cfg: OpenClawConfig = {
|
|
agents: {
|
|
defaults: {
|
|
models: {
|
|
[KILOCODE_DEFAULT_MODEL_REF]: { alias: "My Custom Alias" },
|
|
},
|
|
},
|
|
},
|
|
};
|
|
const result = applyKilocodeProviderConfig(cfg);
|
|
const agentModel = result.agents?.defaults?.models?.[KILOCODE_DEFAULT_MODEL_REF];
|
|
expect(agentModel?.alias).toBe("My Custom Alias");
|
|
});
|
|
|
|
it("does not change the default model selection", () => {
|
|
const cfg: OpenClawConfig = {
|
|
agents: {
|
|
defaults: {
|
|
model: { primary: "openai/gpt-5" },
|
|
},
|
|
},
|
|
};
|
|
const result = applyKilocodeProviderConfig(cfg);
|
|
expect(resolveAgentModelPrimaryValue(result.agents?.defaults?.model)).toBe("openai/gpt-5");
|
|
});
|
|
});
|
|
|
|
describe("applyKilocodeConfig", () => {
|
|
it("sets kilocode as the default model", () => {
|
|
const result = applyKilocodeConfig(emptyCfg);
|
|
expect(resolveAgentModelPrimaryValue(result.agents?.defaults?.model)).toBe(
|
|
KILOCODE_DEFAULT_MODEL_REF,
|
|
);
|
|
});
|
|
|
|
it("also registers the provider", () => {
|
|
const result = applyKilocodeConfig(emptyCfg);
|
|
const provider = result.models?.providers?.kilocode;
|
|
expect(provider).toBeDefined();
|
|
expect(provider?.baseUrl).toBe(KILOCODE_BASE_URL);
|
|
});
|
|
});
|
|
|
|
describe("env var resolution", () => {
|
|
it("resolves KILOCODE_API_KEY from env", () => {
|
|
const envSnapshot = captureEnv(["KILOCODE_API_KEY"]);
|
|
process.env.KILOCODE_API_KEY = "test-kilo-key";
|
|
|
|
try {
|
|
const result = resolveEnvApiKey("kilocode");
|
|
expect(result).not.toBeNull();
|
|
expect(result?.apiKey).toBe("test-kilo-key");
|
|
expect(result?.source).toContain("KILOCODE_API_KEY");
|
|
} finally {
|
|
envSnapshot.restore();
|
|
}
|
|
});
|
|
|
|
it("returns null when KILOCODE_API_KEY is not set", () => {
|
|
const envSnapshot = captureEnv(["KILOCODE_API_KEY"]);
|
|
delete process.env.KILOCODE_API_KEY;
|
|
|
|
try {
|
|
const result = resolveEnvApiKey("kilocode");
|
|
expect(result).toBeNull();
|
|
} finally {
|
|
envSnapshot.restore();
|
|
}
|
|
});
|
|
|
|
it("resolves the kilocode api key via resolveApiKeyForProvider", async () => {
|
|
const agentDir = mkdtempSync(join(tmpdir(), "openclaw-test-"));
|
|
const envSnapshot = captureEnv(["KILOCODE_API_KEY"]);
|
|
process.env.KILOCODE_API_KEY = "kilo-provider-test-key";
|
|
|
|
try {
|
|
const auth = await resolveApiKeyForProvider({
|
|
provider: "kilocode",
|
|
agentDir,
|
|
});
|
|
|
|
expect(auth.apiKey).toBe("kilo-provider-test-key");
|
|
expect(auth.mode).toBe("api-key");
|
|
expect(auth.source).toContain("KILOCODE_API_KEY");
|
|
} finally {
|
|
envSnapshot.restore();
|
|
}
|
|
});
|
|
});
|
|
});
|