Merge 8ea582fe8e into 09be5d45d5
This commit is contained in:
commit
83b785e2c0
@ -2380,6 +2380,8 @@ Notes:
|
||||
- `z.ai/*` and `z-ai/*` are accepted aliases and normalize to `zai/*`.
|
||||
- If `ZAI_API_KEY` is missing, requests to `zai/*` will fail with an auth error at runtime.
|
||||
- Example error: `No API key found for provider "zai".`
|
||||
- Optional: set `ZAI_BASE_URL` to override the `zai` provider endpoint without editing config.
|
||||
(Legacy alias: `Z_AI_BASE_URL`.) Example for Chinese Z.AI endpoint: `ZAI_BASE_URL=https://open.bigmodel.cn/api/paas/v4/`
|
||||
- Z.AI’s general API endpoint is `https://api.z.ai/api/paas/v4`. GLM coding
|
||||
requests use the dedicated Coding endpoint `https://api.z.ai/api/coding/paas/v4`.
|
||||
The built-in `zai` provider uses the Coding endpoint. If you need the general
|
||||
|
||||
@ -86,6 +86,17 @@ const OLLAMA_DEFAULT_COST = {
|
||||
cacheWrite: 0,
|
||||
};
|
||||
|
||||
function normalizeProviderBaseUrl(url: string): string {
|
||||
return url.trim().replace(/\/+$/, "");
|
||||
}
|
||||
|
||||
function resolveZaiBaseUrlEnv(env: NodeJS.ProcessEnv): string | null {
|
||||
// Keep a legacy alias to mirror Z_AI_API_KEY support.
|
||||
const raw = env.ZAI_BASE_URL?.trim() || env.Z_AI_BASE_URL?.trim() || "";
|
||||
if (!raw) return null;
|
||||
return normalizeProviderBaseUrl(raw);
|
||||
}
|
||||
|
||||
interface OllamaModel {
|
||||
name: string;
|
||||
modified_at: string;
|
||||
@ -392,6 +403,12 @@ export async function resolveImplicitProviders(params: {
|
||||
agentDir: string;
|
||||
}): Promise<ModelsConfig["providers"]> {
|
||||
const providers: Record<string, ProviderConfig> = {};
|
||||
const zaiBaseUrl = resolveZaiBaseUrlEnv(process.env);
|
||||
if (zaiBaseUrl) {
|
||||
// Override baseUrl for pi-ai built-in z.ai models without redefining models.
|
||||
// This matches the "models: [] means baseUrl override only" pattern used for Copilot.
|
||||
providers.zai = { baseUrl: zaiBaseUrl, models: [] };
|
||||
}
|
||||
const authStore = ensureAuthProfileStore(params.agentDir, {
|
||||
allowKeychainPrompt: false,
|
||||
});
|
||||
|
||||
64
src/agents/models-config.providers.zai-base-url.test.ts
Normal file
64
src/agents/models-config.providers.zai-base-url.test.ts
Normal file
@ -0,0 +1,64 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { withTempHome as withTempHomeBase } from "../../test/helpers/temp-home.js";
|
||||
import type { MoltbotConfig } from "../config/config.js";
|
||||
|
||||
async function withTempHome<T>(fn: (home: string) => Promise<T>): Promise<T> {
|
||||
return withTempHomeBase(fn, { prefix: "moltbot-zai-baseurl-" });
|
||||
}
|
||||
|
||||
describe("models-config: ZAI_BASE_URL", () => {
|
||||
let prevHome: string | undefined;
|
||||
let prevZaiBaseUrl: string | undefined;
|
||||
let prevZaiLegacyBaseUrl: string | undefined;
|
||||
|
||||
beforeEach(() => {
|
||||
prevHome = process.env.HOME;
|
||||
prevZaiBaseUrl = process.env.ZAI_BASE_URL;
|
||||
prevZaiLegacyBaseUrl = process.env.Z_AI_BASE_URL;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.env.HOME = prevHome;
|
||||
if (prevZaiBaseUrl === undefined) delete process.env.ZAI_BASE_URL;
|
||||
else process.env.ZAI_BASE_URL = prevZaiBaseUrl;
|
||||
if (prevZaiLegacyBaseUrl === undefined) delete process.env.Z_AI_BASE_URL;
|
||||
else process.env.Z_AI_BASE_URL = prevZaiLegacyBaseUrl;
|
||||
});
|
||||
|
||||
it("writes providers.zai.baseUrl from ZAI_BASE_URL (normalized)", async () => {
|
||||
await withTempHome(async () => {
|
||||
vi.resetModules();
|
||||
process.env.ZAI_BASE_URL = "https://proxy.example.test/v1/";
|
||||
delete process.env.Z_AI_BASE_URL;
|
||||
|
||||
const { ensureMoltbotModelsJson } = await import("./models-config.js");
|
||||
const { resolveMoltbotAgentDir } = await import("./agent-paths.js");
|
||||
|
||||
await ensureMoltbotModelsJson({} as MoltbotConfig);
|
||||
|
||||
const raw = await fs.readFile(path.join(resolveMoltbotAgentDir(), "models.json"), "utf8");
|
||||
const parsed = JSON.parse(raw) as { providers?: Record<string, { baseUrl?: string }> };
|
||||
expect(parsed.providers?.zai?.baseUrl).toBe("https://proxy.example.test/v1");
|
||||
});
|
||||
});
|
||||
|
||||
it("supports legacy Z_AI_BASE_URL when ZAI_BASE_URL is unset", async () => {
|
||||
await withTempHome(async () => {
|
||||
vi.resetModules();
|
||||
delete process.env.ZAI_BASE_URL;
|
||||
process.env.Z_AI_BASE_URL = "http://localhost:9999/v1/";
|
||||
|
||||
const { ensureMoltbotModelsJson } = await import("./models-config.js");
|
||||
const { resolveMoltbotAgentDir } = await import("./agent-paths.js");
|
||||
|
||||
await ensureMoltbotModelsJson({} as MoltbotConfig);
|
||||
|
||||
const raw = await fs.readFile(path.join(resolveMoltbotAgentDir(), "models.json"), "utf8");
|
||||
const parsed = JSON.parse(raw) as { providers?: Record<string, { baseUrl?: string }> };
|
||||
expect(parsed.providers?.zai?.baseUrl).toBe("http://localhost:9999/v1");
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user