feat: add Z.AI env support and live test
This commit is contained in:
@@ -5,6 +5,8 @@
|
|||||||
### Features
|
### Features
|
||||||
- Talk mode: continuous speech conversations (macOS/iOS/Android) with ElevenLabs TTS, reply directives, and optional interrupt-on-speech.
|
- Talk mode: continuous speech conversations (macOS/iOS/Android) with ElevenLabs TTS, reply directives, and optional interrupt-on-speech.
|
||||||
- UI: add optional `ui.seamColor` accent to tint the Talk Mode side bubble (macOS/iOS/Android).
|
- UI: add optional `ui.seamColor` accent to tint the Talk Mode side bubble (macOS/iOS/Android).
|
||||||
|
- Agent runtime: accept legacy `Z_AI_API_KEY` for Z.AI provider auth (maps to `ZAI_API_KEY`).
|
||||||
|
- Tests: add a Z.AI live test gate for smoke validation when keys are present.
|
||||||
|
|
||||||
### Fixes
|
### Fixes
|
||||||
- Docs/agent tools: clarify that browser `wait` should be avoided by default and used only in exceptional cases.
|
- Docs/agent tools: clarify that browser `wait` should be avoided by default and used only in exceptional cases.
|
||||||
|
|||||||
@@ -259,6 +259,8 @@ Controls the embedded agent runtime (model/thinking/verbose/timeouts).
|
|||||||
If `modelAliases` is configured, you may also use the alias key (e.g. `Opus`).
|
If `modelAliases` is configured, you may also use the alias key (e.g. `Opus`).
|
||||||
If you omit the provider, CLAWDIS currently assumes `anthropic` as a temporary
|
If you omit the provider, CLAWDIS currently assumes `anthropic` as a temporary
|
||||||
deprecation fallback.
|
deprecation fallback.
|
||||||
|
Z.AI models are available as `zai/<model>` (e.g. `zai/glm-4.7`) and require
|
||||||
|
`ZAI_API_KEY` (or legacy `Z_AI_API_KEY`) in the environment.
|
||||||
|
|
||||||
`agent.heartbeat` configures periodic heartbeat runs:
|
`agent.heartbeat` configures periodic heartbeat runs:
|
||||||
- `every`: duration string (`ms`, `s`, `m`, `h`); default unit minutes. Omit or set
|
- `every`: duration string (`ms`, `s`, `m`, `h`); default unit minutes. Omit or set
|
||||||
|
|||||||
31
src/agents/zai.live.test.ts
Normal file
31
src/agents/zai.live.test.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { completeSimple, getModel } from "@mariozechner/pi-ai";
|
||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
const ZAI_KEY = process.env.ZAI_API_KEY ?? process.env.Z_AI_API_KEY ?? "";
|
||||||
|
const LIVE = process.env.ZAI_LIVE_TEST === "1" || process.env.LIVE === "1";
|
||||||
|
|
||||||
|
const describeLive = LIVE && ZAI_KEY ? describe : describe.skip;
|
||||||
|
|
||||||
|
describeLive("zai live", () => {
|
||||||
|
it("returns assistant text", async () => {
|
||||||
|
const model = getModel("zai", "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);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -17,6 +17,7 @@ import {
|
|||||||
saveSessionStore,
|
saveSessionStore,
|
||||||
} from "./config/sessions.js";
|
} from "./config/sessions.js";
|
||||||
import { ensureBinary } from "./infra/binaries.js";
|
import { ensureBinary } from "./infra/binaries.js";
|
||||||
|
import { normalizeEnv } from "./infra/env.js";
|
||||||
import { isMainModule } from "./infra/is-main.js";
|
import { isMainModule } from "./infra/is-main.js";
|
||||||
import { ensureClawdisCliOnPath } from "./infra/path-env.js";
|
import { ensureClawdisCliOnPath } from "./infra/path-env.js";
|
||||||
import {
|
import {
|
||||||
@@ -32,6 +33,7 @@ import { monitorWebProvider } from "./provider-web.js";
|
|||||||
import { assertProvider, normalizeE164, toWhatsappJid } from "./utils.js";
|
import { assertProvider, normalizeE164, toWhatsappJid } from "./utils.js";
|
||||||
|
|
||||||
dotenv.config({ quiet: true });
|
dotenv.config({ quiet: true });
|
||||||
|
normalizeEnv();
|
||||||
ensureClawdisCliOnPath();
|
ensureClawdisCliOnPath();
|
||||||
|
|
||||||
// Capture all console output into structured logs while keeping stdout/stderr behavior.
|
// Capture all console output into structured logs while keeping stdout/stderr behavior.
|
||||||
|
|||||||
37
src/infra/env.test.ts
Normal file
37
src/infra/env.test.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
import { normalizeZaiEnv } from "./env.js";
|
||||||
|
|
||||||
|
describe("normalizeZaiEnv", () => {
|
||||||
|
it("copies Z_AI_API_KEY to ZAI_API_KEY when missing", () => {
|
||||||
|
const prevZai = process.env.ZAI_API_KEY;
|
||||||
|
const prevZAi = process.env.Z_AI_API_KEY;
|
||||||
|
process.env.ZAI_API_KEY = "";
|
||||||
|
process.env.Z_AI_API_KEY = "zai-legacy";
|
||||||
|
|
||||||
|
normalizeZaiEnv();
|
||||||
|
|
||||||
|
expect(process.env.ZAI_API_KEY).toBe("zai-legacy");
|
||||||
|
|
||||||
|
if (prevZai === undefined) delete process.env.ZAI_API_KEY;
|
||||||
|
else process.env.ZAI_API_KEY = prevZai;
|
||||||
|
if (prevZAi === undefined) delete process.env.Z_AI_API_KEY;
|
||||||
|
else process.env.Z_AI_API_KEY = prevZAi;
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not override existing ZAI_API_KEY", () => {
|
||||||
|
const prevZai = process.env.ZAI_API_KEY;
|
||||||
|
const prevZAi = process.env.Z_AI_API_KEY;
|
||||||
|
process.env.ZAI_API_KEY = "zai-current";
|
||||||
|
process.env.Z_AI_API_KEY = "zai-legacy";
|
||||||
|
|
||||||
|
normalizeZaiEnv();
|
||||||
|
|
||||||
|
expect(process.env.ZAI_API_KEY).toBe("zai-current");
|
||||||
|
|
||||||
|
if (prevZai === undefined) delete process.env.ZAI_API_KEY;
|
||||||
|
else process.env.ZAI_API_KEY = prevZai;
|
||||||
|
if (prevZAi === undefined) delete process.env.Z_AI_API_KEY;
|
||||||
|
else process.env.Z_AI_API_KEY = prevZAi;
|
||||||
|
});
|
||||||
|
});
|
||||||
9
src/infra/env.ts
Normal file
9
src/infra/env.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
export function normalizeZaiEnv(): void {
|
||||||
|
if (!process.env.ZAI_API_KEY?.trim() && process.env.Z_AI_API_KEY?.trim()) {
|
||||||
|
process.env.ZAI_API_KEY = process.env.Z_AI_API_KEY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeEnv(): void {
|
||||||
|
normalizeZaiEnv();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user