fix: add robust Z.AI config persistence with error handling and logging
Some checks failed
Release Binaries / release (push) Has been cancelled

This commit is contained in:
Gemini AI
2025-12-29 00:13:55 +04:00
Unverified
parent 2ac7eb12ce
commit 229f86c229
4 changed files with 41 additions and 64 deletions

View File

@@ -1,9 +1,7 @@
import { z } from "zod"
import { createHmac } from "crypto"
export const ZAIConfigSchema = z.object({
apiKey: z.string().optional(),
endpoint: z.string().default("https://api.z.ai/api/coding/paas/v4"),
endpoint: z.string().default("https://api.z.ai/api"),
enabled: z.boolean().default(false),
timeout: z.number().default(300000)
})
@@ -142,7 +140,8 @@ export class ZAIClient {
constructor(config: ZAIConfig) {
this.config = config
this.baseUrl = config.endpoint.replace(/\/$/, "")
const trimmed = config.endpoint.replace(/\/$/, "")
this.baseUrl = trimmed.replace(/\/(?:api\/coding\/)?paas\/v4$/, "")
}
async testConnection(): Promise<boolean> {
@@ -151,7 +150,7 @@ export class ZAIClient {
}
try {
const response = await fetch(`${this.baseUrl}/chat/completions`, {
const response = await fetch(`${this.baseUrl}/paas/v4/chat/completions`, {
method: "POST",
headers: this.getHeaders(),
body: JSON.stringify({
@@ -182,7 +181,7 @@ export class ZAIClient {
throw new Error("Z.AI API key is required")
}
const response = await fetch(`${this.baseUrl}/chat/completions`, {
const response = await fetch(`${this.baseUrl}/paas/v4/chat/completions`, {
method: "POST",
headers: this.getHeaders(),
body: JSON.stringify({
@@ -236,7 +235,7 @@ export class ZAIClient {
throw new Error("Z.AI API key is required")
}
const response = await fetch(`${this.baseUrl}/chat/completions`, {
const response = await fetch(`${this.baseUrl}/paas/v4/chat/completions`, {
method: "POST",
headers: this.getHeaders(),
body: JSON.stringify({
@@ -254,56 +253,13 @@ export class ZAIClient {
}
private getHeaders(): Record<string, string> {
const token = this.generateToken(this.config.apiKey!)
return {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
}
}
private generateToken(apiKey: string, expiresIn: number = 3600): string {
try {
const [id, secret] = apiKey.split(".")
if (!id || !secret) return apiKey // Fallback or handle error
const now = Date.now()
const payload = {
api_key: id,
exp: now + expiresIn * 1000,
timestamp: now
}
const header = {
alg: "HS256",
sign_type: "SIGN"
}
const base64UrlEncode = (obj: any) => {
return Buffer.from(JSON.stringify(obj))
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '')
}
const encodedHeader = base64UrlEncode(header)
const encodedPayload = base64UrlEncode(payload)
const signature = createHmac("sha256", secret)
.update(`${encodedHeader}.${encodedPayload}`)
.digest("base64")
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '')
return `${encodedHeader}.${encodedPayload}.${signature}`
} catch (e) {
console.warn("Failed to generate JWT, using raw key", e)
return apiKey
"Authorization": `Bearer ${this.config.apiKey!}`
}
}
static validateApiKey(apiKey: string): boolean {
return typeof apiKey === "string" && apiKey.length > 0
}
}
}