test(models): cover merge auth/baseUrl precedence

This commit is contained in:
Gustavo Madeira Santana
2026-02-26 03:30:12 -05:00
parent ee26a90bf5
commit b7841d8d16
2 changed files with 91 additions and 0 deletions

View File

@@ -0,0 +1 @@
- Fix models merge to preserve agent-level provider `apiKey` and `baseUrl` when present (#27293) (thanks @Sid-Qin)

View File

@@ -134,6 +134,96 @@ describe("models-config", () => {
});
});
it("preserves non-empty agent apiKey/baseUrl for matching providers in merge mode", async () => {
await withTempHome(async () => {
const agentDir = resolveOpenClawAgentDir();
await fs.mkdir(agentDir, { recursive: true });
await fs.writeFile(
path.join(agentDir, "models.json"),
JSON.stringify(
{
providers: {
custom: {
baseUrl: "https://agent.example/v1",
apiKey: "AGENT_KEY",
api: "openai-responses",
models: [{ id: "agent-model", name: "Agent model", input: ["text"] }],
},
},
},
null,
2,
),
"utf8",
);
await ensureOpenClawModelsJson({
models: {
mode: "merge",
providers: {
custom: {
baseUrl: "https://config.example/v1",
apiKey: "CONFIG_KEY",
api: "openai-responses",
models: [{ id: "config-model", name: "Config model", input: ["text"] }],
},
},
},
});
const parsed = await readGeneratedModelsJson<{
providers: Record<string, { apiKey?: string; baseUrl?: string }>;
}>();
expect(parsed.providers.custom?.apiKey).toBe("AGENT_KEY");
expect(parsed.providers.custom?.baseUrl).toBe("https://agent.example/v1");
});
});
it("uses config apiKey/baseUrl when existing agent values are empty", async () => {
await withTempHome(async () => {
const agentDir = resolveOpenClawAgentDir();
await fs.mkdir(agentDir, { recursive: true });
await fs.writeFile(
path.join(agentDir, "models.json"),
JSON.stringify(
{
providers: {
custom: {
baseUrl: "",
apiKey: "",
api: "openai-responses",
models: [{ id: "agent-model", name: "Agent model", input: ["text"] }],
},
},
},
null,
2,
),
"utf8",
);
await ensureOpenClawModelsJson({
models: {
mode: "merge",
providers: {
custom: {
baseUrl: "https://config.example/v1",
apiKey: "CONFIG_KEY",
api: "openai-responses",
models: [{ id: "config-model", name: "Config model", input: ["text"] }],
},
},
},
});
const parsed = await readGeneratedModelsJson<{
providers: Record<string, { apiKey?: string; baseUrl?: string }>;
}>();
expect(parsed.providers.custom?.apiKey).toBe("CONFIG_KEY");
expect(parsed.providers.custom?.baseUrl).toBe("https://config.example/v1");
});
});
it("refreshes stale explicit moonshot model capabilities from implicit catalog", async () => {
await withTempHome(async () => {
const prevKey = process.env.MOONSHOT_API_KEY;