mirror of
https://github.com/farcasclaudiu/openclaw.git
synced 2026-06-29 15:01:48 +03:00
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -73,6 +73,7 @@ docs/.local/
|
|||||||
IDENTITY.md
|
IDENTITY.md
|
||||||
USER.md
|
USER.md
|
||||||
.tgz
|
.tgz
|
||||||
|
.idea
|
||||||
|
|
||||||
# local tooling
|
# local tooling
|
||||||
.serena/
|
.serena/
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ Docs: https://docs.openclaw.ai
|
|||||||
- Slack: detect control commands when channel messages start with bot mention prefixes (for example, `@Bot /new`). (#14142) Thanks @beefiker.
|
- Slack: detect control commands when channel messages start with bot mention prefixes (for example, `@Bot /new`). (#14142) Thanks @beefiker.
|
||||||
- Discord tests: use a partial @buape/carbon mock in slash command coverage. (#13262) Thanks @arosstale.
|
- Discord tests: use a partial @buape/carbon mock in slash command coverage. (#13262) Thanks @arosstale.
|
||||||
- CLI/Wizard: exit with code 1 when `configure`, `agents add`, or interactive `onboard` wizards are canceled, so `set -e` automation stops correctly. (#14156) Thanks @0xRaini.
|
- CLI/Wizard: exit with code 1 when `configure`, `agents add`, or interactive `onboard` wizards are canceled, so `set -e` automation stops correctly. (#14156) Thanks @0xRaini.
|
||||||
|
- Onboarding/Providers: add Z.AI endpoint-specific auth choices (`zai-coding-global`, `zai-coding-cn`, `zai-global`, `zai-cn`) and expand default Z.AI model wiring. (#13456) Thanks @tomsun28.
|
||||||
- Feishu: pass `Buffer` directly to the Feishu SDK upload APIs instead of `Readable.from(...)` to avoid form-data upload failures. (#10345) Thanks @youngerstyle.
|
- Feishu: pass `Buffer` directly to the Feishu SDK upload APIs instead of `Readable.from(...)` to avoid form-data upload failures. (#10345) Thanks @youngerstyle.
|
||||||
- Feishu: trigger mention-gated group handling only when the bot itself is mentioned (not just any mention). (#11088) Thanks @openperf.
|
- Feishu: trigger mention-gated group handling only when the bot itself is mentioned (not just any mention). (#11088) Thanks @openperf.
|
||||||
- Feishu: probe status uses the resolved account context for multi-account credential checks. (#11233) Thanks @onevcat.
|
- Feishu: probe status uses the resolved account context for multi-account credential checks. (#11233) Thanks @onevcat.
|
||||||
|
|||||||
@@ -39,6 +39,20 @@ openclaw onboard --non-interactive \
|
|||||||
|
|
||||||
`--custom-api-key` is optional in non-interactive mode. If omitted, onboarding checks `CUSTOM_API_KEY`.
|
`--custom-api-key` is optional in non-interactive mode. If omitted, onboarding checks `CUSTOM_API_KEY`.
|
||||||
|
|
||||||
|
Non-interactive Z.AI endpoint choices:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Promptless endpoint selection
|
||||||
|
openclaw onboard --non-interactive \
|
||||||
|
--auth-choice zai-coding-global \
|
||||||
|
--zai-api-key "$ZAI_API_KEY"
|
||||||
|
|
||||||
|
# Other Z.AI endpoint choices:
|
||||||
|
# --auth-choice zai-coding-cn
|
||||||
|
# --auth-choice zai-global
|
||||||
|
# --auth-choice zai-cn
|
||||||
|
```
|
||||||
|
|
||||||
Flow notes:
|
Flow notes:
|
||||||
|
|
||||||
- `quickstart`: minimal prompts, auto-generates a gateway token.
|
- `quickstart`: minimal prompts, auto-generates a gateway token.
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ const CODEX_MODELS = [
|
|||||||
"gpt-5.1-codex-max",
|
"gpt-5.1-codex-max",
|
||||||
];
|
];
|
||||||
const GOOGLE_PREFIXES = ["gemini-3"];
|
const GOOGLE_PREFIXES = ["gemini-3"];
|
||||||
const ZAI_PREFIXES = ["glm-4.7"];
|
const ZAI_PREFIXES = ["glm-5", "glm-4.7", "glm-4.7-flash", "glm-4.7-flashx"];
|
||||||
const MINIMAX_PREFIXES = ["minimax-m2.1"];
|
const MINIMAX_PREFIXES = ["minimax-m2.1"];
|
||||||
const XAI_PREFIXES = ["grok-4"];
|
const XAI_PREFIXES = ["grok-4"];
|
||||||
|
|
||||||
|
|||||||
@@ -29,4 +29,26 @@ describeLive("zai live", () => {
|
|||||||
.join(" ");
|
.join(" ");
|
||||||
expect(text.length).toBeGreaterThan(0);
|
expect(text.length).toBeGreaterThan(0);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
|
it("glm-4.7-flashx returns assistant text", async () => {
|
||||||
|
const model = getModel("zai", "glm-4.7-flashx" as "glm-4.7");
|
||||||
|
const res = await completeSimple(
|
||||||
|
model,
|
||||||
|
{
|
||||||
|
messages: [
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
content: "Reply with the word ok.",
|
||||||
|
timestamp: Date.now(),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{ apiKey: ZAI_KEY, maxTokens: 64 },
|
||||||
|
);
|
||||||
|
const text = res.content
|
||||||
|
.filter((block) => block.type === "text")
|
||||||
|
.map((block) => block.text.trim())
|
||||||
|
.join(" ");
|
||||||
|
expect(text.length).toBeGreaterThan(0);
|
||||||
|
}, 20000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export function registerOnboardCommand(program: Command) {
|
|||||||
.option("--mode <mode>", "Wizard mode: local|remote")
|
.option("--mode <mode>", "Wizard mode: local|remote")
|
||||||
.option(
|
.option(
|
||||||
"--auth-choice <choice>",
|
"--auth-choice <choice>",
|
||||||
"Auth: setup-token|token|chutes|openai-codex|openai-api-key|xai-api-key|qianfan-api-key|openrouter-api-key|litellm-api-key|ai-gateway-api-key|cloudflare-ai-gateway-api-key|moonshot-api-key|moonshot-api-key-cn|kimi-code-api-key|synthetic-api-key|venice-api-key|gemini-api-key|zai-api-key|xiaomi-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|custom-api-key|skip|together-api-key",
|
"Auth: setup-token|token|chutes|openai-codex|openai-api-key|xai-api-key|qianfan-api-key|openrouter-api-key|litellm-api-key|ai-gateway-api-key|cloudflare-ai-gateway-api-key|moonshot-api-key|moonshot-api-key-cn|kimi-code-api-key|synthetic-api-key|venice-api-key|gemini-api-key|zai-api-key|zai-coding-global|zai-coding-cn|zai-global|zai-cn|xiaomi-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|custom-api-key|skip|together-api-key",
|
||||||
)
|
)
|
||||||
.option(
|
.option(
|
||||||
"--token-provider <id>",
|
"--token-provider <id>",
|
||||||
|
|||||||
@@ -92,9 +92,9 @@ const AUTH_CHOICE_GROUP_DEFS: {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "zai",
|
value: "zai",
|
||||||
label: "Z.AI (GLM 4.7)",
|
label: "Z.AI",
|
||||||
hint: "API key",
|
hint: "GLM Coding Plan / Global / CN",
|
||||||
choices: ["zai-api-key"],
|
choices: ["zai-coding-global", "zai-coding-cn", "zai-global", "zai-cn"],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: "qianfan",
|
value: "qianfan",
|
||||||
@@ -242,7 +242,27 @@ export function buildAuthChoiceOptions(params: {
|
|||||||
label: "Google Gemini CLI OAuth",
|
label: "Google Gemini CLI OAuth",
|
||||||
hint: "Uses the bundled Gemini CLI auth plugin",
|
hint: "Uses the bundled Gemini CLI auth plugin",
|
||||||
});
|
});
|
||||||
options.push({ value: "zai-api-key", label: "Z.AI (GLM 4.7) API key" });
|
options.push({ value: "zai-api-key", label: "Z.AI API key" });
|
||||||
|
options.push({
|
||||||
|
value: "zai-coding-global",
|
||||||
|
label: "Coding-Plan-Global",
|
||||||
|
hint: "GLM Coding Plan Global (api.z.ai)",
|
||||||
|
});
|
||||||
|
options.push({
|
||||||
|
value: "zai-coding-cn",
|
||||||
|
label: "Coding-Plan-CN",
|
||||||
|
hint: "GLM Coding Plan CN (open.bigmodel.cn)",
|
||||||
|
});
|
||||||
|
options.push({
|
||||||
|
value: "zai-global",
|
||||||
|
label: "Global",
|
||||||
|
hint: "Z.AI Global (api.z.ai)",
|
||||||
|
});
|
||||||
|
options.push({
|
||||||
|
value: "zai-cn",
|
||||||
|
label: "CN",
|
||||||
|
hint: "Z.AI CN (open.bigmodel.cn)",
|
||||||
|
});
|
||||||
options.push({
|
options.push({
|
||||||
value: "xiaomi-api-key",
|
value: "xiaomi-api-key",
|
||||||
label: "Xiaomi API key",
|
label: "Xiaomi API key",
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import {
|
|||||||
applyXiaomiConfig,
|
applyXiaomiConfig,
|
||||||
applyXiaomiProviderConfig,
|
applyXiaomiProviderConfig,
|
||||||
applyZaiConfig,
|
applyZaiConfig,
|
||||||
|
applyZaiProviderConfig,
|
||||||
CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF,
|
CLOUDFLARE_AI_GATEWAY_DEFAULT_MODEL_REF,
|
||||||
LITELLM_DEFAULT_MODEL_REF,
|
LITELLM_DEFAULT_MODEL_REF,
|
||||||
QIANFAN_DEFAULT_MODEL_REF,
|
QIANFAN_DEFAULT_MODEL_REF,
|
||||||
@@ -619,7 +620,54 @@ export async function applyAuthChoiceApiProviders(
|
|||||||
return { config: nextConfig, agentModelOverride };
|
return { config: nextConfig, agentModelOverride };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authChoice === "zai-api-key") {
|
if (
|
||||||
|
authChoice === "zai-api-key" ||
|
||||||
|
authChoice === "zai-coding-global" ||
|
||||||
|
authChoice === "zai-coding-cn" ||
|
||||||
|
authChoice === "zai-global" ||
|
||||||
|
authChoice === "zai-cn"
|
||||||
|
) {
|
||||||
|
// Determine endpoint from authChoice or prompt
|
||||||
|
let endpoint: string;
|
||||||
|
if (authChoice === "zai-coding-global") {
|
||||||
|
endpoint = "coding-global";
|
||||||
|
} else if (authChoice === "zai-coding-cn") {
|
||||||
|
endpoint = "coding-cn";
|
||||||
|
} else if (authChoice === "zai-global") {
|
||||||
|
endpoint = "global";
|
||||||
|
} else if (authChoice === "zai-cn") {
|
||||||
|
endpoint = "cn";
|
||||||
|
} else {
|
||||||
|
// zai-api-key: prompt for endpoint selection
|
||||||
|
endpoint = await params.prompter.select({
|
||||||
|
message: "Select Z.AI endpoint",
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
value: "coding-global",
|
||||||
|
label: "Coding-Plan-Global",
|
||||||
|
hint: "GLM Coding Plan Global (api.z.ai)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "coding-cn",
|
||||||
|
label: "Coding-Plan-CN",
|
||||||
|
hint: "GLM Coding Plan CN (open.bigmodel.cn)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "global",
|
||||||
|
label: "Global",
|
||||||
|
hint: "Z.AI Global (api.z.ai)",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: "cn",
|
||||||
|
label: "CN",
|
||||||
|
hint: "Z.AI CN (open.bigmodel.cn)",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
initialValue: "coding-global",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Input API key
|
||||||
let hasCredential = false;
|
let hasCredential = false;
|
||||||
|
|
||||||
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "zai") {
|
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "zai") {
|
||||||
@@ -655,23 +703,8 @@ export async function applyAuthChoiceApiProviders(
|
|||||||
config: nextConfig,
|
config: nextConfig,
|
||||||
setDefaultModel: params.setDefaultModel,
|
setDefaultModel: params.setDefaultModel,
|
||||||
defaultModel: ZAI_DEFAULT_MODEL_REF,
|
defaultModel: ZAI_DEFAULT_MODEL_REF,
|
||||||
applyDefaultConfig: applyZaiConfig,
|
applyDefaultConfig: (config) => applyZaiConfig(config, { endpoint }),
|
||||||
applyProviderConfig: (config) => ({
|
applyProviderConfig: (config) => applyZaiProviderConfig(config, { endpoint }),
|
||||||
...config,
|
|
||||||
agents: {
|
|
||||||
...config.agents,
|
|
||||||
defaults: {
|
|
||||||
...config.agents?.defaults,
|
|
||||||
models: {
|
|
||||||
...config.agents?.defaults?.models,
|
|
||||||
[ZAI_DEFAULT_MODEL_REF]: {
|
|
||||||
...config.agents?.defaults?.models?.[ZAI_DEFAULT_MODEL_REF],
|
|
||||||
alias: config.agents?.defaults?.models?.[ZAI_DEFAULT_MODEL_REF]?.alias ?? "GLM",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
noteDefault: ZAI_DEFAULT_MODEL_REF,
|
noteDefault: ZAI_DEFAULT_MODEL_REF,
|
||||||
noteAgentModel,
|
noteAgentModel,
|
||||||
prompter: params.prompter,
|
prompter: params.prompter,
|
||||||
|
|||||||
@@ -20,6 +20,10 @@ const PREFERRED_PROVIDER_BY_AUTH_CHOICE: Partial<Record<AuthChoice, string>> = {
|
|||||||
"google-antigravity": "google-antigravity",
|
"google-antigravity": "google-antigravity",
|
||||||
"google-gemini-cli": "google-gemini-cli",
|
"google-gemini-cli": "google-gemini-cli",
|
||||||
"zai-api-key": "zai",
|
"zai-api-key": "zai",
|
||||||
|
"zai-coding-global": "zai",
|
||||||
|
"zai-coding-cn": "zai",
|
||||||
|
"zai-global": "zai",
|
||||||
|
"zai-cn": "zai",
|
||||||
"xiaomi-api-key": "xiaomi",
|
"xiaomi-api-key": "xiaomi",
|
||||||
"synthetic-api-key": "synthetic",
|
"synthetic-api-key": "synthetic",
|
||||||
"venice-api-key": "venice",
|
"venice-api-key": "venice",
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import type { RuntimeEnv } from "../runtime.js";
|
|||||||
import type { WizardPrompter } from "../wizard/prompts.js";
|
import type { WizardPrompter } from "../wizard/prompts.js";
|
||||||
import type { AuthChoice } from "./onboard-types.js";
|
import type { AuthChoice } from "./onboard-types.js";
|
||||||
import { applyAuthChoice, resolvePreferredProviderForAuthChoice } from "./auth-choice.js";
|
import { applyAuthChoice, resolvePreferredProviderForAuthChoice } from "./auth-choice.js";
|
||||||
|
import { ZAI_CODING_CN_BASE_URL, ZAI_CODING_GLOBAL_BASE_URL } from "./onboard-auth.js";
|
||||||
|
|
||||||
vi.mock("../providers/github-copilot-auth.js", () => ({
|
vi.mock("../providers/github-copilot-auth.js", () => ({
|
||||||
githubCopilotLoginCommand: vi.fn(async () => {}),
|
githubCopilotLoginCommand: vi.fn(async () => {}),
|
||||||
@@ -199,6 +200,101 @@ describe("applyAuthChoice", () => {
|
|||||||
expect(parsed.profiles?.["synthetic:default"]?.key).toBe("sk-synthetic-test");
|
expect(parsed.profiles?.["synthetic:default"]?.key).toBe("sk-synthetic-test");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("prompts for Z.AI endpoint when selecting zai-api-key", async () => {
|
||||||
|
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||||
|
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||||
|
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||||
|
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||||
|
|
||||||
|
const text = vi.fn().mockResolvedValue("zai-test-key");
|
||||||
|
const select = vi.fn(async (params: { message: string }) => {
|
||||||
|
if (params.message === "Select Z.AI endpoint") {
|
||||||
|
return "coding-cn";
|
||||||
|
}
|
||||||
|
return "default";
|
||||||
|
});
|
||||||
|
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||||
|
const prompter: WizardPrompter = {
|
||||||
|
intro: vi.fn(noopAsync),
|
||||||
|
outro: vi.fn(noopAsync),
|
||||||
|
note: vi.fn(noopAsync),
|
||||||
|
select: select as WizardPrompter["select"],
|
||||||
|
multiselect,
|
||||||
|
text,
|
||||||
|
confirm: vi.fn(async () => false),
|
||||||
|
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||||
|
};
|
||||||
|
const runtime: RuntimeEnv = {
|
||||||
|
log: vi.fn(),
|
||||||
|
error: vi.fn(),
|
||||||
|
exit: vi.fn((code: number) => {
|
||||||
|
throw new Error(`exit:${code}`);
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await applyAuthChoice({
|
||||||
|
authChoice: "zai-api-key",
|
||||||
|
config: {},
|
||||||
|
prompter,
|
||||||
|
runtime,
|
||||||
|
setDefaultModel: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(select).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({ message: "Select Z.AI endpoint", initialValue: "coding-global" }),
|
||||||
|
);
|
||||||
|
expect(result.config.models?.providers?.zai?.baseUrl).toBe(ZAI_CODING_CN_BASE_URL);
|
||||||
|
expect(result.config.agents?.defaults?.model?.primary).toBe("zai/glm-4.7");
|
||||||
|
|
||||||
|
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||||
|
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||||
|
const parsed = JSON.parse(raw) as {
|
||||||
|
profiles?: Record<string, { key?: string }>;
|
||||||
|
};
|
||||||
|
expect(parsed.profiles?.["zai:default"]?.key).toBe("zai-test-key");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses endpoint-specific auth choice without prompting for Z.AI endpoint", async () => {
|
||||||
|
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||||
|
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||||
|
process.env.OPENCLAW_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||||
|
process.env.PI_CODING_AGENT_DIR = process.env.OPENCLAW_AGENT_DIR;
|
||||||
|
|
||||||
|
const text = vi.fn().mockResolvedValue("zai-test-key");
|
||||||
|
const select = vi.fn(async () => "default");
|
||||||
|
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||||
|
const prompter: WizardPrompter = {
|
||||||
|
intro: vi.fn(noopAsync),
|
||||||
|
outro: vi.fn(noopAsync),
|
||||||
|
note: vi.fn(noopAsync),
|
||||||
|
select: select as WizardPrompter["select"],
|
||||||
|
multiselect,
|
||||||
|
text,
|
||||||
|
confirm: vi.fn(async () => false),
|
||||||
|
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||||
|
};
|
||||||
|
const runtime: RuntimeEnv = {
|
||||||
|
log: vi.fn(),
|
||||||
|
error: vi.fn(),
|
||||||
|
exit: vi.fn((code: number) => {
|
||||||
|
throw new Error(`exit:${code}`);
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await applyAuthChoice({
|
||||||
|
authChoice: "zai-coding-global",
|
||||||
|
config: {},
|
||||||
|
prompter,
|
||||||
|
runtime,
|
||||||
|
setDefaultModel: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(select).not.toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({ message: "Select Z.AI endpoint" }),
|
||||||
|
);
|
||||||
|
expect(result.config.models?.providers?.zai?.baseUrl).toBe(ZAI_CODING_GLOBAL_BASE_URL);
|
||||||
|
});
|
||||||
|
|
||||||
it("does not override the global default model when selecting xai-api-key without setDefaultModel", async () => {
|
it("does not override the global default model when selecting xai-api-key without setDefaultModel", async () => {
|
||||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-"));
|
||||||
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
process.env.OPENCLAW_STATE_DIR = tempStateDir;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import {
|
|||||||
XAI_DEFAULT_MODEL_REF,
|
XAI_DEFAULT_MODEL_REF,
|
||||||
} from "./onboard-auth.credentials.js";
|
} from "./onboard-auth.credentials.js";
|
||||||
import {
|
import {
|
||||||
|
buildZaiModelDefinition,
|
||||||
buildMoonshotModelDefinition,
|
buildMoonshotModelDefinition,
|
||||||
buildXaiModelDefinition,
|
buildXaiModelDefinition,
|
||||||
QIANFAN_BASE_URL,
|
QIANFAN_BASE_URL,
|
||||||
@@ -47,18 +48,65 @@ import {
|
|||||||
MOONSHOT_CN_BASE_URL,
|
MOONSHOT_CN_BASE_URL,
|
||||||
MOONSHOT_DEFAULT_MODEL_ID,
|
MOONSHOT_DEFAULT_MODEL_ID,
|
||||||
MOONSHOT_DEFAULT_MODEL_REF,
|
MOONSHOT_DEFAULT_MODEL_REF,
|
||||||
|
ZAI_DEFAULT_MODEL_ID,
|
||||||
|
resolveZaiBaseUrl,
|
||||||
XAI_BASE_URL,
|
XAI_BASE_URL,
|
||||||
XAI_DEFAULT_MODEL_ID,
|
XAI_DEFAULT_MODEL_ID,
|
||||||
} from "./onboard-auth.models.js";
|
} from "./onboard-auth.models.js";
|
||||||
|
|
||||||
export function applyZaiConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyZaiProviderConfig(
|
||||||
|
cfg: OpenClawConfig,
|
||||||
|
params?: { endpoint?: string; modelId?: string },
|
||||||
|
): OpenClawConfig {
|
||||||
|
const modelId = params?.modelId?.trim() || ZAI_DEFAULT_MODEL_ID;
|
||||||
|
const modelRef = `zai/${modelId}`;
|
||||||
|
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
const models = { ...cfg.agents?.defaults?.models };
|
||||||
models[ZAI_DEFAULT_MODEL_REF] = {
|
models[modelRef] = {
|
||||||
...models[ZAI_DEFAULT_MODEL_REF],
|
...models[modelRef],
|
||||||
alias: models[ZAI_DEFAULT_MODEL_REF]?.alias ?? "GLM",
|
alias: models[modelRef]?.alias ?? "GLM",
|
||||||
|
};
|
||||||
|
|
||||||
|
const providers = { ...cfg.models?.providers };
|
||||||
|
const existingProvider = providers.zai;
|
||||||
|
const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : [];
|
||||||
|
|
||||||
|
const defaultModels = [
|
||||||
|
buildZaiModelDefinition({ id: "glm-5" }),
|
||||||
|
buildZaiModelDefinition({ id: "glm-4.7" }),
|
||||||
|
buildZaiModelDefinition({ id: "glm-4.7-flash" }),
|
||||||
|
buildZaiModelDefinition({ id: "glm-4.7-flashx" }),
|
||||||
|
];
|
||||||
|
|
||||||
|
const mergedModels = [...existingModels];
|
||||||
|
const seen = new Set(existingModels.map((m) => m.id));
|
||||||
|
for (const model of defaultModels) {
|
||||||
|
if (!seen.has(model.id)) {
|
||||||
|
mergedModels.push(model);
|
||||||
|
seen.add(model.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as Record<
|
||||||
|
string,
|
||||||
|
unknown
|
||||||
|
> as { apiKey?: string };
|
||||||
|
const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined;
|
||||||
|
const normalizedApiKey = resolvedApiKey?.trim();
|
||||||
|
|
||||||
|
const baseUrl = params?.endpoint
|
||||||
|
? resolveZaiBaseUrl(params.endpoint)
|
||||||
|
: (typeof existingProvider?.baseUrl === "string" ? existingProvider.baseUrl : "") ||
|
||||||
|
resolveZaiBaseUrl();
|
||||||
|
|
||||||
|
providers.zai = {
|
||||||
|
...existingProviderRest,
|
||||||
|
baseUrl,
|
||||||
|
api: "openai-completions",
|
||||||
|
...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}),
|
||||||
|
models: mergedModels.length > 0 ? mergedModels : defaultModels,
|
||||||
};
|
};
|
||||||
|
|
||||||
const existingModel = cfg.agents?.defaults?.model;
|
|
||||||
return {
|
return {
|
||||||
...cfg,
|
...cfg,
|
||||||
agents: {
|
agents: {
|
||||||
@@ -66,13 +114,37 @@ export function applyZaiConfig(cfg: OpenClawConfig): OpenClawConfig {
|
|||||||
defaults: {
|
defaults: {
|
||||||
...cfg.agents?.defaults,
|
...cfg.agents?.defaults,
|
||||||
models,
|
models,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
models: {
|
||||||
|
mode: cfg.models?.mode ?? "merge",
|
||||||
|
providers,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyZaiConfig(
|
||||||
|
cfg: OpenClawConfig,
|
||||||
|
params?: { endpoint?: string; modelId?: string },
|
||||||
|
): OpenClawConfig {
|
||||||
|
const modelId = params?.modelId?.trim() || ZAI_DEFAULT_MODEL_ID;
|
||||||
|
const modelRef = modelId === ZAI_DEFAULT_MODEL_ID ? ZAI_DEFAULT_MODEL_REF : `zai/${modelId}`;
|
||||||
|
const next = applyZaiProviderConfig(cfg, params);
|
||||||
|
|
||||||
|
const existingModel = next.agents?.defaults?.model;
|
||||||
|
return {
|
||||||
|
...next,
|
||||||
|
agents: {
|
||||||
|
...next.agents,
|
||||||
|
defaults: {
|
||||||
|
...next.agents?.defaults,
|
||||||
model: {
|
model: {
|
||||||
...(existingModel && "fallbacks" in (existingModel as Record<string, unknown>)
|
...(existingModel && "fallbacks" in (existingModel as Record<string, unknown>)
|
||||||
? {
|
? {
|
||||||
fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks,
|
fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks,
|
||||||
}
|
}
|
||||||
: undefined),
|
: undefined),
|
||||||
primary: ZAI_DEFAULT_MODEL_REF,
|
primary: modelRef,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -20,6 +20,26 @@ export const KIMI_CODING_MODEL_REF = `kimi-coding/${KIMI_CODING_MODEL_ID}`;
|
|||||||
export { QIANFAN_BASE_URL, QIANFAN_DEFAULT_MODEL_ID };
|
export { QIANFAN_BASE_URL, QIANFAN_DEFAULT_MODEL_ID };
|
||||||
export const QIANFAN_DEFAULT_MODEL_REF = `qianfan/${QIANFAN_DEFAULT_MODEL_ID}`;
|
export const QIANFAN_DEFAULT_MODEL_REF = `qianfan/${QIANFAN_DEFAULT_MODEL_ID}`;
|
||||||
|
|
||||||
|
export const ZAI_CODING_GLOBAL_BASE_URL = "https://api.z.ai/api/coding/paas/v4";
|
||||||
|
export const ZAI_CODING_CN_BASE_URL = "https://open.bigmodel.cn/api/coding/paas/v4";
|
||||||
|
export const ZAI_GLOBAL_BASE_URL = "https://api.z.ai/api/paas/v4";
|
||||||
|
export const ZAI_CN_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
|
||||||
|
export const ZAI_DEFAULT_MODEL_ID = "glm-4.7";
|
||||||
|
|
||||||
|
export function resolveZaiBaseUrl(endpoint?: string): string {
|
||||||
|
switch (endpoint) {
|
||||||
|
case "coding-cn":
|
||||||
|
return ZAI_CODING_CN_BASE_URL;
|
||||||
|
case "global":
|
||||||
|
return ZAI_GLOBAL_BASE_URL;
|
||||||
|
case "cn":
|
||||||
|
return ZAI_CN_BASE_URL;
|
||||||
|
case "coding-global":
|
||||||
|
default:
|
||||||
|
return ZAI_CODING_GLOBAL_BASE_URL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Pricing: MiniMax doesn't publish public rates. Override in models.json for accurate costs.
|
// Pricing: MiniMax doesn't publish public rates. Override in models.json for accurate costs.
|
||||||
export const MINIMAX_API_COST = {
|
export const MINIMAX_API_COST = {
|
||||||
input: 15,
|
input: 15,
|
||||||
@@ -46,6 +66,13 @@ export const MOONSHOT_DEFAULT_COST = {
|
|||||||
cacheWrite: 0,
|
cacheWrite: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ZAI_DEFAULT_COST = {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
};
|
||||||
|
|
||||||
const MINIMAX_MODEL_CATALOG = {
|
const MINIMAX_MODEL_CATALOG = {
|
||||||
"MiniMax-M2.1": { name: "MiniMax M2.1", reasoning: false },
|
"MiniMax-M2.1": { name: "MiniMax M2.1", reasoning: false },
|
||||||
"MiniMax-M2.1-lightning": {
|
"MiniMax-M2.1-lightning": {
|
||||||
@@ -56,6 +83,15 @@ const MINIMAX_MODEL_CATALOG = {
|
|||||||
|
|
||||||
type MinimaxCatalogId = keyof typeof MINIMAX_MODEL_CATALOG;
|
type MinimaxCatalogId = keyof typeof MINIMAX_MODEL_CATALOG;
|
||||||
|
|
||||||
|
const ZAI_MODEL_CATALOG = {
|
||||||
|
"glm-5": { name: "GLM-5", reasoning: true },
|
||||||
|
"glm-4.7": { name: "GLM-4.7", reasoning: true },
|
||||||
|
"glm-4.7-flash": { name: "GLM-4.7 Flash", reasoning: true },
|
||||||
|
"glm-4.7-flashx": { name: "GLM-4.7 FlashX", reasoning: true },
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
type ZaiCatalogId = keyof typeof ZAI_MODEL_CATALOG;
|
||||||
|
|
||||||
export function buildMinimaxModelDefinition(params: {
|
export function buildMinimaxModelDefinition(params: {
|
||||||
id: string;
|
id: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
@@ -97,6 +133,26 @@ export function buildMoonshotModelDefinition(): ModelDefinitionConfig {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function buildZaiModelDefinition(params: {
|
||||||
|
id: string;
|
||||||
|
name?: string;
|
||||||
|
reasoning?: boolean;
|
||||||
|
cost?: ModelDefinitionConfig["cost"];
|
||||||
|
contextWindow?: number;
|
||||||
|
maxTokens?: number;
|
||||||
|
}): ModelDefinitionConfig {
|
||||||
|
const catalog = ZAI_MODEL_CATALOG[params.id as ZaiCatalogId];
|
||||||
|
return {
|
||||||
|
id: params.id,
|
||||||
|
name: params.name ?? catalog?.name ?? `GLM ${params.id}`,
|
||||||
|
reasoning: params.reasoning ?? catalog?.reasoning ?? true,
|
||||||
|
input: ["text"],
|
||||||
|
cost: params.cost ?? ZAI_DEFAULT_COST,
|
||||||
|
contextWindow: params.contextWindow ?? 204800,
|
||||||
|
maxTokens: params.maxTokens ?? 131072,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export const XAI_BASE_URL = "https://api.x.ai/v1";
|
export const XAI_BASE_URL = "https://api.x.ai/v1";
|
||||||
export const XAI_DEFAULT_MODEL_ID = "grok-4";
|
export const XAI_DEFAULT_MODEL_ID = "grok-4";
|
||||||
export const XAI_DEFAULT_MODEL_REF = `xai/${XAI_DEFAULT_MODEL_ID}`;
|
export const XAI_DEFAULT_MODEL_REF = `xai/${XAI_DEFAULT_MODEL_ID}`;
|
||||||
|
|||||||
@@ -18,12 +18,16 @@ import {
|
|||||||
applyXaiProviderConfig,
|
applyXaiProviderConfig,
|
||||||
applyXiaomiConfig,
|
applyXiaomiConfig,
|
||||||
applyXiaomiProviderConfig,
|
applyXiaomiProviderConfig,
|
||||||
|
applyZaiConfig,
|
||||||
|
applyZaiProviderConfig,
|
||||||
OPENROUTER_DEFAULT_MODEL_REF,
|
OPENROUTER_DEFAULT_MODEL_REF,
|
||||||
SYNTHETIC_DEFAULT_MODEL_ID,
|
SYNTHETIC_DEFAULT_MODEL_ID,
|
||||||
SYNTHETIC_DEFAULT_MODEL_REF,
|
SYNTHETIC_DEFAULT_MODEL_REF,
|
||||||
XAI_DEFAULT_MODEL_REF,
|
XAI_DEFAULT_MODEL_REF,
|
||||||
setMinimaxApiKey,
|
setMinimaxApiKey,
|
||||||
writeOAuthCredentials,
|
writeOAuthCredentials,
|
||||||
|
ZAI_CODING_CN_BASE_URL,
|
||||||
|
ZAI_CODING_GLOBAL_BASE_URL,
|
||||||
} from "./onboard-auth.js";
|
} from "./onboard-auth.js";
|
||||||
|
|
||||||
const authProfilePathFor = (agentDir: string) => path.join(agentDir, "auth-profiles.json");
|
const authProfilePathFor = (agentDir: string) => path.join(agentDir, "auth-profiles.json");
|
||||||
@@ -303,6 +307,47 @@ describe("applyMinimaxApiProviderConfig", () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe("applyZaiConfig", () => {
|
||||||
|
it("adds zai provider with correct settings", () => {
|
||||||
|
const cfg = applyZaiConfig({});
|
||||||
|
expect(cfg.models?.providers?.zai).toMatchObject({
|
||||||
|
baseUrl: ZAI_CODING_GLOBAL_BASE_URL,
|
||||||
|
api: "openai-completions",
|
||||||
|
});
|
||||||
|
const ids = cfg.models?.providers?.zai?.models?.map((m) => m.id);
|
||||||
|
expect(ids).toContain("glm-5");
|
||||||
|
expect(ids).toContain("glm-4.7");
|
||||||
|
expect(ids).toContain("glm-4.7-flash");
|
||||||
|
expect(ids).toContain("glm-4.7-flashx");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets correct primary model", () => {
|
||||||
|
const cfg = applyZaiConfig({}, { modelId: "glm-5" });
|
||||||
|
expect(cfg.agents?.defaults?.model?.primary).toBe("zai/glm-5");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("supports CN endpoint", () => {
|
||||||
|
const cfg = applyZaiConfig({}, { endpoint: "coding-cn", modelId: "glm-4.7-flash" });
|
||||||
|
expect(cfg.models?.providers?.zai?.baseUrl).toBe(ZAI_CODING_CN_BASE_URL);
|
||||||
|
expect(cfg.agents?.defaults?.model?.primary).toBe("zai/glm-4.7-flash");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("supports CN endpoint with glm-4.7-flashx", () => {
|
||||||
|
const cfg = applyZaiConfig({}, { endpoint: "coding-cn", modelId: "glm-4.7-flashx" });
|
||||||
|
expect(cfg.models?.providers?.zai?.baseUrl).toBe(ZAI_CODING_CN_BASE_URL);
|
||||||
|
expect(cfg.agents?.defaults?.model?.primary).toBe("zai/glm-4.7-flashx");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("applyZaiProviderConfig", () => {
|
||||||
|
it("does not overwrite existing primary model", () => {
|
||||||
|
const cfg = applyZaiProviderConfig({
|
||||||
|
agents: { defaults: { model: { primary: "anthropic/claude-opus-4-5" } } },
|
||||||
|
});
|
||||||
|
expect(cfg.agents?.defaults?.model?.primary).toBe("anthropic/claude-opus-4-5");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe("applySyntheticConfig", () => {
|
describe("applySyntheticConfig", () => {
|
||||||
it("adds synthetic provider with correct settings", () => {
|
it("adds synthetic provider with correct settings", () => {
|
||||||
const cfg = applySyntheticConfig({});
|
const cfg = applySyntheticConfig({});
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export {
|
|||||||
applyXiaomiConfig,
|
applyXiaomiConfig,
|
||||||
applyXiaomiProviderConfig,
|
applyXiaomiProviderConfig,
|
||||||
applyZaiConfig,
|
applyZaiConfig,
|
||||||
|
applyZaiProviderConfig,
|
||||||
} from "./onboard-auth.config-core.js";
|
} from "./onboard-auth.config-core.js";
|
||||||
export {
|
export {
|
||||||
applyMinimaxApiConfig,
|
applyMinimaxApiConfig,
|
||||||
@@ -78,6 +79,7 @@ export {
|
|||||||
buildMinimaxApiModelDefinition,
|
buildMinimaxApiModelDefinition,
|
||||||
buildMinimaxModelDefinition,
|
buildMinimaxModelDefinition,
|
||||||
buildMoonshotModelDefinition,
|
buildMoonshotModelDefinition,
|
||||||
|
buildZaiModelDefinition,
|
||||||
DEFAULT_MINIMAX_BASE_URL,
|
DEFAULT_MINIMAX_BASE_URL,
|
||||||
MOONSHOT_CN_BASE_URL,
|
MOONSHOT_CN_BASE_URL,
|
||||||
QIANFAN_BASE_URL,
|
QIANFAN_BASE_URL,
|
||||||
@@ -91,4 +93,10 @@ export {
|
|||||||
MOONSHOT_BASE_URL,
|
MOONSHOT_BASE_URL,
|
||||||
MOONSHOT_DEFAULT_MODEL_ID,
|
MOONSHOT_DEFAULT_MODEL_ID,
|
||||||
MOONSHOT_DEFAULT_MODEL_REF,
|
MOONSHOT_DEFAULT_MODEL_REF,
|
||||||
|
resolveZaiBaseUrl,
|
||||||
|
ZAI_CODING_CN_BASE_URL,
|
||||||
|
ZAI_DEFAULT_MODEL_ID,
|
||||||
|
ZAI_CODING_GLOBAL_BASE_URL,
|
||||||
|
ZAI_CN_BASE_URL,
|
||||||
|
ZAI_GLOBAL_BASE_URL,
|
||||||
} from "./onboard-auth.models.js";
|
} from "./onboard-auth.models.js";
|
||||||
|
|||||||
@@ -139,6 +139,60 @@ async function expectApiKeyProfile(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("onboard (non-interactive): provider auth", () => {
|
describe("onboard (non-interactive): provider auth", () => {
|
||||||
|
it("stores Z.AI API key and uses coding-global baseUrl by default", async () => {
|
||||||
|
await withOnboardEnv("openclaw-onboard-zai-", async ({ configPath, runtime }) => {
|
||||||
|
await runNonInteractive(
|
||||||
|
{
|
||||||
|
nonInteractive: true,
|
||||||
|
authChoice: "zai-api-key",
|
||||||
|
zaiApiKey: "zai-test-key",
|
||||||
|
skipHealth: true,
|
||||||
|
skipChannels: true,
|
||||||
|
skipSkills: true,
|
||||||
|
json: true,
|
||||||
|
},
|
||||||
|
runtime,
|
||||||
|
);
|
||||||
|
|
||||||
|
const cfg = await readJsonFile<{
|
||||||
|
auth?: { profiles?: Record<string, { provider?: string; mode?: string }> };
|
||||||
|
agents?: { defaults?: { model?: { primary?: string } } };
|
||||||
|
models?: { providers?: Record<string, { baseUrl?: string }> };
|
||||||
|
}>(configPath);
|
||||||
|
|
||||||
|
expect(cfg.auth?.profiles?.["zai:default"]?.provider).toBe("zai");
|
||||||
|
expect(cfg.auth?.profiles?.["zai:default"]?.mode).toBe("api_key");
|
||||||
|
expect(cfg.models?.providers?.zai?.baseUrl).toBe("https://api.z.ai/api/coding/paas/v4");
|
||||||
|
expect(cfg.agents?.defaults?.model?.primary).toBe("zai/glm-4.7");
|
||||||
|
await expectApiKeyProfile({ profileId: "zai:default", provider: "zai", key: "zai-test-key" });
|
||||||
|
});
|
||||||
|
}, 60_000);
|
||||||
|
|
||||||
|
it("supports Z.AI CN coding endpoint auth choice", async () => {
|
||||||
|
await withOnboardEnv("openclaw-onboard-zai-cn-", async ({ configPath, runtime }) => {
|
||||||
|
await runNonInteractive(
|
||||||
|
{
|
||||||
|
nonInteractive: true,
|
||||||
|
authChoice: "zai-coding-cn",
|
||||||
|
zaiApiKey: "zai-test-key",
|
||||||
|
skipHealth: true,
|
||||||
|
skipChannels: true,
|
||||||
|
skipSkills: true,
|
||||||
|
json: true,
|
||||||
|
},
|
||||||
|
runtime,
|
||||||
|
);
|
||||||
|
|
||||||
|
const cfg = await readJsonFile<{
|
||||||
|
models?: { providers?: Record<string, { baseUrl?: string }> };
|
||||||
|
}>(configPath);
|
||||||
|
|
||||||
|
expect(cfg.models?.providers?.zai?.baseUrl).toBe(
|
||||||
|
"https://open.bigmodel.cn/api/coding/paas/v4",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}, 60_000);
|
||||||
|
|
||||||
it("stores xAI API key and sets default model", async () => {
|
it("stores xAI API key and sets default model", async () => {
|
||||||
await withOnboardEnv("openclaw-onboard-xai-", async ({ configPath, runtime }) => {
|
await withOnboardEnv("openclaw-onboard-xai-", async ({ configPath, runtime }) => {
|
||||||
await runNonInteractive(
|
await runNonInteractive(
|
||||||
|
|||||||
@@ -187,7 +187,13 @@ export async function applyNonInteractiveAuthChoice(params: {
|
|||||||
return applyGoogleGeminiModelDefault(nextConfig).next;
|
return applyGoogleGeminiModelDefault(nextConfig).next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authChoice === "zai-api-key") {
|
if (
|
||||||
|
authChoice === "zai-api-key" ||
|
||||||
|
authChoice === "zai-coding-global" ||
|
||||||
|
authChoice === "zai-coding-cn" ||
|
||||||
|
authChoice === "zai-global" ||
|
||||||
|
authChoice === "zai-cn"
|
||||||
|
) {
|
||||||
const resolved = await resolveNonInteractiveApiKey({
|
const resolved = await resolveNonInteractiveApiKey({
|
||||||
provider: "zai",
|
provider: "zai",
|
||||||
cfg: baseConfig,
|
cfg: baseConfig,
|
||||||
@@ -207,7 +213,21 @@ export async function applyNonInteractiveAuthChoice(params: {
|
|||||||
provider: "zai",
|
provider: "zai",
|
||||||
mode: "api_key",
|
mode: "api_key",
|
||||||
});
|
});
|
||||||
return applyZaiConfig(nextConfig);
|
|
||||||
|
// Determine endpoint from authChoice or opts
|
||||||
|
let endpoint: "global" | "cn" | "coding-global" | "coding-cn" | undefined;
|
||||||
|
if (authChoice === "zai-coding-global") {
|
||||||
|
endpoint = "coding-global";
|
||||||
|
} else if (authChoice === "zai-coding-cn") {
|
||||||
|
endpoint = "coding-cn";
|
||||||
|
} else if (authChoice === "zai-global") {
|
||||||
|
endpoint = "global";
|
||||||
|
} else if (authChoice === "zai-cn") {
|
||||||
|
endpoint = "cn";
|
||||||
|
} else {
|
||||||
|
endpoint = "coding-global";
|
||||||
|
}
|
||||||
|
return applyZaiConfig(nextConfig, { endpoint });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (authChoice === "xiaomi-api-key") {
|
if (authChoice === "xiaomi-api-key") {
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ export type AuthChoice =
|
|||||||
| "google-antigravity"
|
| "google-antigravity"
|
||||||
| "google-gemini-cli"
|
| "google-gemini-cli"
|
||||||
| "zai-api-key"
|
| "zai-api-key"
|
||||||
|
| "zai-coding-global"
|
||||||
|
| "zai-coding-cn"
|
||||||
|
| "zai-global"
|
||||||
|
| "zai-cn"
|
||||||
| "xiaomi-api-key"
|
| "xiaomi-api-key"
|
||||||
| "minimax-cloud"
|
| "minimax-cloud"
|
||||||
| "minimax"
|
| "minimax"
|
||||||
|
|||||||
Reference in New Issue
Block a user