feat(zai): add Z.AI GLM Coding Plan provider preset (#896)
* feat(zai): add Z.AI GLM Coding Plan provider preset Add dedicated Z.AI provider support for the GLM Coding Plan, enabling use of GLM-5.1, GLM-5-Turbo, GLM-4.7, and GLM-4.5-Air models through the OpenAI-compatible shim with proper thinking mode (reasoning_content), max_tokens handling, and context window sizing. * fix(zai): unify GLM max output token limits across casing variants glm-5/glm-4.7 had conservative 16K max output while GLM-5/GLM-4.7 had 131K. Use consistent Z.AI coding plan limits for all GLM variants. * fix(zai): restore DashScope GLM limits, enable GLM thinking support - Restore lowercase glm-5/glm-4.7 to 16_384 max output (DashScope limits) while keeping Z.AI coding plan high limits on uppercase GLM-* keys only - Add GLM model support to modelSupportsThinking() so reasoning_content is enabled when using GLM-5.x/GLM-4.7 models on Z.AI * fix(zai): tighten GLM regexes, fix misleading context window comment - Use precise regex in thinking.ts: exact GLM model matches only, no false positives on glm-50/glm-4, includes glm-4.5-air - Use uppercase-only match in StartupScreen rawModel fallback so DashScope lowercase glm-* models aren't mislabeled as Z.AI - Clarify context window comment: lowercase glm-5.1/glm-5-turbo/ glm-4.5-air are Z.AI-specific aliases, not DashScope * fix(zai): scope GLM detection to Z.AI * improve readability of max_completion_tokens check Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -64,6 +64,7 @@ import {
|
||||
} from './openaiErrorClassification.js'
|
||||
import { sanitizeSchemaForOpenAICompat } from '../../utils/schemaSanitizer.js'
|
||||
import { redactSecretValueForDisplay } from '../../utils/providerProfile.js'
|
||||
import { isZaiBaseUrl } from '../../utils/zaiProvider.js'
|
||||
import {
|
||||
normalizeToolArguments,
|
||||
hasToolFieldMapping,
|
||||
@@ -93,7 +94,6 @@ const KIMI_CODE_API_HOST = 'api.kimi.com'
|
||||
const DEEPSEEK_API_HOSTS = new Set([
|
||||
'api.deepseek.com',
|
||||
])
|
||||
|
||||
const COPILOT_HEADERS: Record<string, string> = {
|
||||
'User-Agent': 'GitHubCopilotChat/0.26.7',
|
||||
'Editor-Version': 'vscode/1.99.3',
|
||||
@@ -1514,7 +1514,8 @@ class OpenAIShimMessages {
|
||||
// thinking block we captured on the inbound response.
|
||||
preserveReasoningContent:
|
||||
isMoonshotCompatibleBaseUrl(request.baseUrl) ||
|
||||
isDeepSeekBaseUrl(request.baseUrl),
|
||||
isDeepSeekBaseUrl(request.baseUrl) ||
|
||||
isZaiBaseUrl(request.baseUrl),
|
||||
})
|
||||
|
||||
const body: Record<string, unknown> = {
|
||||
@@ -1553,8 +1554,19 @@ class OpenAIShimMessages {
|
||||
|
||||
const isMoonshot = isMoonshotCompatibleBaseUrl(request.baseUrl)
|
||||
const isDeepSeek = isDeepSeekBaseUrl(request.baseUrl)
|
||||
const isZai = isZaiBaseUrl(request.baseUrl)
|
||||
|
||||
if ((isGithub || isMistral || isLocal || isMoonshot || isDeepSeek) && body.max_completion_tokens !== undefined) {
|
||||
if (
|
||||
(
|
||||
isGithub ||
|
||||
isMistral ||
|
||||
isLocal ||
|
||||
isMoonshot ||
|
||||
isDeepSeek ||
|
||||
isZai
|
||||
) &&
|
||||
body.max_completion_tokens !== undefined
|
||||
) {
|
||||
body.max_tokens = body.max_completion_tokens
|
||||
delete body.max_completion_tokens
|
||||
}
|
||||
@@ -1562,10 +1574,10 @@ class OpenAIShimMessages {
|
||||
// mistral and gemini don't recognize body.store — Gemini returns 400
|
||||
// "Invalid JSON payload received. Unknown name 'store': Cannot find field."
|
||||
// Moonshot direct API, Kimi Code's OpenAI-compatible coding endpoint,
|
||||
// and DeepSeek have not published support for the parameter either;
|
||||
// DeepSeek, and Z.AI have not published support for the parameter either;
|
||||
// strip it preemptively to avoid the same class of error on strict-parse
|
||||
// providers.
|
||||
if (isMistral || isGeminiMode() || isMoonshot || isDeepSeek) {
|
||||
if (isMistral || isGeminiMode() || isMoonshot || isDeepSeek || isZai) {
|
||||
delete body.store
|
||||
}
|
||||
|
||||
@@ -1593,6 +1605,17 @@ class OpenAIShimMessages {
|
||||
}
|
||||
}
|
||||
|
||||
// Z.AI uses the same thinking format as DeepSeek: { type: "enabled" | "disabled" }
|
||||
// with reasoning_content in responses.
|
||||
if (isZai) {
|
||||
const requestedThinkingType = (params.thinking as { type?: string } | undefined)?.type
|
||||
if (requestedThinkingType && requestedThinkingType !== 'disabled') {
|
||||
body.thinking = { type: 'enabled' }
|
||||
} else if (requestedThinkingType === 'disabled') {
|
||||
body.thinking = { type: 'disabled' }
|
||||
}
|
||||
}
|
||||
|
||||
if (params.tools && params.tools.length > 0) {
|
||||
const converted = convertTools(
|
||||
params.tools as Array<{
|
||||
|
||||
Reference in New Issue
Block a user