Skip to content

Commit ec77e3f

Browse files
zoomote[bot]navedmerchant
andauthored
feat(providers): add GLM-5.3-Flash support (#1430)
Co-authored-by: @navedmerchant <14171946+navedmerchant@users.noreply.github.com>
1 parent 1dbe3bd commit ec77e3f

8 files changed

Lines changed: 125 additions & 8 deletions

File tree

‎packages/types/src/__tests__/lite-llm.test.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ describe("LiteLLM preserveReasoning model detection", () => {
2121
it("matches case-insensitively", () => {
2222
expect(isLiteLLMPreserveReasoningModel("MiniMax-M2.7-Highspeed")).toBe(true)
2323
expect(isLiteLLMPreserveReasoningModel("GLM-5.3")).toBe(true)
24+
expect(isLiteLLMPreserveReasoningModel("GLM-5.3-FLASH")).toBe(true)
2425
expect(isLiteLLMPreserveReasoningModel("QWEN3.8-MAX")).toBe(true)
2526
})
2627

‎packages/types/src/providers/lite-llm.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ export const LITELLM_PRESERVE_REASONING_MODEL_IDS = [
5555
"glm-5.1",
5656
"glm-5.2",
5757
"glm-5.3",
58+
"glm-5.3-flash",
5859
"glm-5-turbo",
5960

6061
// bedrock.ts, minimax.ts, opencode-go.ts

‎packages/types/src/providers/zai.ts‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { ZaiApiLine } from "../provider-settings.js"
66
// https://docs.z.ai/guides/llm/glm-4.5
77
// https://docs.z.ai/guides/llm/glm-4.6
88
// https://docs.z.ai/guides/llm/glm-5.3
9+
// https://docs.z.ai/guides/vlm/glm-5.3-flash
910
// https://docs.z.ai/guides/llm/glm-5.1
1011
// https://docs.z.ai/guides/llm/glm-5-turbo
1112
// https://docs.z.ai/guides/overview/pricing
@@ -26,6 +27,13 @@ const glm53ModelInfo = {
2627
"GLM-5.3 is Zhipu's flagship coding and agent model with a 1M context window, 128k max output, and always-on reasoning with configurable effort (Low/High/Max).",
2728
} as const satisfies ModelInfo
2829

30+
const glm53FlashModelInfo = {
31+
...glm53ModelInfo,
32+
supportsImages: true,
33+
description:
34+
"GLM-5.3-Flash is Zhipu's efficient multimodal coding and agent model with a 1M context window, 128k max output, and always-on reasoning with configurable effort (Low/High/Max).",
35+
} as const satisfies ModelInfo
36+
2937
export type InternationalZAiModelId = keyof typeof internationalZAiModels
3038
export const internationalZAiDefaultModelId: InternationalZAiModelId = "glm-4.7"
3139
export const internationalZAiModels = {
@@ -193,6 +201,13 @@ export const internationalZAiModels = {
193201
cacheWritesPrice: 0,
194202
cacheReadsPrice: 0.26,
195203
},
204+
"glm-5.3-flash": {
205+
...glm53FlashModelInfo,
206+
inputPrice: 0.15,
207+
outputPrice: 0.5,
208+
cacheWritesPrice: 0,
209+
cacheReadsPrice: 0.03,
210+
},
196211
"glm-5-turbo": {
197212
maxTokens: 131_072,
198213
contextWindow: 202_752,
@@ -505,6 +520,13 @@ export const mainlandZAiCodingPlanOnlyModels = {
505520
cacheWritesPrice: 0,
506521
cacheReadsPrice: 0.13,
507522
},
523+
"glm-5.3-flash": {
524+
...glm53FlashModelInfo,
525+
inputPrice: 0.075,
526+
outputPrice: 0.25,
527+
cacheWritesPrice: 0,
528+
cacheReadsPrice: 0.015,
529+
},
508530
} as const satisfies Record<string, ModelInfo>
509531

510532
export const ZAI_DEFAULT_TEMPERATURE = 0.6

‎src/api/providers/__tests__/zai.spec.ts‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,31 @@ describe("ZAiHandler", () => {
167167
expect(model.info.cacheReadsPrice).toBe(0.26)
168168
})
169169

170+
it("should expose multimodal GLM-5.3-Flash for the international Coding Plan", () => {
171+
const model = new ZAiHandler({
172+
apiModelId: "glm-5.3-flash",
173+
zaiApiKey: "test-zai-api-key",
174+
zaiApiLine: "international_coding",
175+
}).getModel()
176+
177+
expect(model.id).toBe("glm-5.3-flash")
178+
expect(model.info).toMatchObject({
179+
contextWindow: 1_000_000,
180+
maxTokens: 131_072,
181+
supportsImages: true,
182+
supportsPromptCache: true,
183+
supportsMaxTokens: true,
184+
supportsReasoningEffort: ["low", "high", "max"],
185+
requiredReasoningEffort: true,
186+
reasoningEffort: "max",
187+
preserveReasoning: true,
188+
defaultTemperature: 1,
189+
inputPrice: 0.15,
190+
outputPrice: 0.5,
191+
cacheReadsPrice: 0.03,
192+
})
193+
})
194+
170195
it("should return GLM-5-Turbo international model with thinking support", () => {
171196
const testModelId: InternationalZAiModelId = "glm-5-turbo"
172197
const handlerWithModel = new ZAiHandler({
@@ -319,6 +344,22 @@ describe("ZAiHandler", () => {
319344
expect(model.info.cacheReadsPrice).toBe(0.13)
320345
})
321346

347+
it("should expose GLM-5.3-Flash for the China Coding Plan", () => {
348+
const model = new ZAiHandler({
349+
apiModelId: "glm-5.3-flash",
350+
zaiApiKey: "test-zai-api-key",
351+
zaiApiLine: "china_coding",
352+
}).getModel()
353+
354+
expect(model.id).toBe("glm-5.3-flash")
355+
expect(model.info.supportsImages).toBe(true)
356+
expect(model.info.supportsReasoningEffort).toEqual(["low", "high", "max"])
357+
expect(model.info.requiredReasoningEffort).toBe(true)
358+
expect(model.info.inputPrice).toBe(0.075)
359+
expect(model.info.outputPrice).toBe(0.25)
360+
expect(model.info.cacheReadsPrice).toBe(0.015)
361+
})
362+
322363
it("should return GLM-4.7 China model with thinking support", () => {
323364
const testModelId: MainlandZAiModelId = "glm-4.7"
324365
const handlerWithModel = new ZAiHandler({
@@ -393,6 +434,7 @@ describe("ZAiHandler", () => {
393434

394435
it("should expose GLM-5.3 on the international API", () => {
395436
expect(getZAiModels("international_api")).toHaveProperty("glm-5.3")
437+
expect(getZAiModels("international_api")).toHaveProperty("glm-5.3-flash")
396438
const handlerWithModel = new ZAiHandler({
397439
apiModelId: "glm-5.3",
398440
zaiApiKey: "test-zai-api-key",
@@ -442,6 +484,7 @@ describe("ZAiHandler", () => {
442484

443485
it("should not expose Coding Plan-only models", () => {
444486
expect(getZAiModels("china_api")).not.toHaveProperty("glm-5.3")
487+
expect(getZAiModels("china_api")).not.toHaveProperty("glm-5.3-flash")
445488
})
446489
})
447490

@@ -692,6 +735,29 @@ describe("ZAiHandler", () => {
692735
)
693736
})
694737

738+
it("should use the official GLM-5.3-Flash thinking and sampling defaults", async () => {
739+
const handlerWithModel = new ZAiHandler({
740+
apiModelId: "glm-5.3-flash",
741+
zaiApiKey: "test-zai-api-key",
742+
zaiApiLine: "international_coding",
743+
reasoningEffort: "disable",
744+
})
745+
746+
mockCreate.mockImplementationOnce(() => asyncStreamFrom([]))
747+
748+
const messageGenerator = handlerWithModel.createMessage("system prompt", [])
749+
await messageGenerator.next()
750+
751+
expect(mockCreate).toHaveBeenCalledWith(
752+
expect.objectContaining({
753+
model: "glm-5.3-flash",
754+
thinking: { type: "enabled", clear_thinking: false },
755+
reasoning_effort: "max",
756+
temperature: 1,
757+
}),
758+
)
759+
})
760+
695761
it("should keep GLM-5.3 reasoning enabled when the master reasoning setting is disabled", async () => {
696762
const handlerWithModel = new ZAiHandler({
697763
apiModelId: "glm-5.3",
@@ -734,6 +800,26 @@ describe("ZAiHandler", () => {
734800
})
735801
})
736802

803+
it("should use the official GLM-5.3-Flash parameters for completePrompt", async () => {
804+
const handlerWithModel = new ZAiHandler({
805+
apiModelId: "glm-5.3-flash",
806+
zaiApiKey: "test-zai-api-key",
807+
zaiApiLine: "international_api",
808+
reasoningEffort: "low",
809+
})
810+
811+
mockCreate.mockResolvedValueOnce({ choices: [{ message: { content: "response" } }] })
812+
813+
await expect(handlerWithModel.completePrompt("prompt")).resolves.toBe("response")
814+
expect(mockCreate).toHaveBeenCalledWith({
815+
model: "glm-5.3-flash",
816+
messages: [{ role: "user", content: "prompt" }],
817+
temperature: 1,
818+
thinking: { type: "enabled", clear_thinking: false },
819+
reasoning_effort: "low",
820+
})
821+
})
822+
737823
it("should omit reasoning_effort for GLM-5.2 when reasoningEffort is set to disable", async () => {
738824
const handlerWithModel = new ZAiHandler({
739825
apiModelId: "glm-5.2",

‎src/api/providers/fetchers/__tests__/litellm.spec.ts‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,7 @@ describe("getLiteLLMModels", () => {
765765
data: {
766766
data: [
767767
{
768-
model_name: "glm-5.3",
768+
model_name: "glm-5.3-flash",
769769
model_info: {
770770
max_tokens: 8192,
771771
max_input_tokens: 128000,
@@ -782,7 +782,7 @@ describe("getLiteLLMModels", () => {
782782

783783
const result = await getLiteLLMModels("test-api-key", "http://localhost:4000")
784784

785-
expect(result["glm-5.3"]).toMatchObject({ preserveReasoning: true })
785+
expect(result["glm-5.3-flash"]).toMatchObject({ preserveReasoning: true })
786786
})
787787

788788
it("does not match a model id that merely contains a known family as a substring", async () => {

‎src/api/providers/zai.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ type ZAiChatCompletionParams = Omit<OpenAI.Chat.ChatCompletionCreateParams, "rea
2727
reasoning_effort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"
2828
}
2929

30+
const isGlm53Model = (model: string) => model === "glm-5.3" || model === "glm-5.3-flash"
31+
3032
export class ZAiHandler extends BaseOpenAiCompatibleProvider<string> {
3133
constructor(options: ApiHandlerOptions) {
3234
const apiLine = options.zaiApiLine ?? "international_coding"
@@ -105,7 +107,7 @@ export class ZAiHandler extends BaseOpenAiCompatibleProvider<string> {
105107
stream_options: { include_usage: true },
106108
// Models with required reasoning stay enabled even when an old setting requests disable.
107109
thinking: useReasoning
108-
? { type: "enabled", ...(model === "glm-5.3" && { clear_thinking: false }) }
110+
? { type: "enabled", ...(isGlm53Model(model) && { clear_thinking: false }) }
109111
: { type: "disabled" },
110112
reasoning_effort: reasoningEffort,
111113
tools: this.convertToolsForOpenAI(metadata?.tools),
@@ -143,7 +145,7 @@ export class ZAiHandler extends BaseOpenAiCompatibleProvider<string> {
143145

144146
override async completePrompt(prompt: string, options?: CompletePromptOptions): Promise<string> {
145147
const { id: model, info } = this.getModel()
146-
if (model !== "glm-5.3") {
148+
if (!isGlm53Model(model)) {
147149
return super.completePrompt(prompt, options)
148150
}
149151

‎webview-ui/src/components/settings/utils/__tests__/providerModelConfig.spec.ts‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ describe("providerModelConfig", () => {
206206
expect(Object.keys(models).length).toBe(0)
207207
})
208208

209-
it("shows GLM-5.3 for international Z.ai API and Coding Plan entrypoints", () => {
209+
it("shows GLM-5.3 models for international Z.ai API and Coding Plan entrypoints", () => {
210210
const internationalCoding = getStaticModelsForProvider("zai", undefined, {
211211
apiProvider: "zai",
212212
zaiApiLine: "international_coding",
@@ -225,9 +225,13 @@ describe("providerModelConfig", () => {
225225
})
226226

227227
expect(internationalCoding).toHaveProperty("glm-5.3")
228+
expect(internationalCoding).toHaveProperty("glm-5.3-flash")
228229
expect(chinaCoding).toHaveProperty("glm-5.3")
230+
expect(chinaCoding).toHaveProperty("glm-5.3-flash")
229231
expect(internationalApi).toHaveProperty("glm-5.3")
232+
expect(internationalApi).toHaveProperty("glm-5.3-flash")
230233
expect(chinaApi).not.toHaveProperty("glm-5.3")
234+
expect(chinaApi).not.toHaveProperty("glm-5.3-flash")
231235
})
232236
})
233237

‎webview-ui/src/components/ui/hooks/__tests__/useSelectedModel.spec.ts‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1331,13 +1331,14 @@ describe("useSelectedModel", () => {
13311331
it("uses the International Coding catalog when no API line is configured", () => {
13321332
const apiConfiguration: ProviderSettings = {
13331333
apiProvider: providerIdentifiers.zai,
1334-
apiModelId: "glm-5.3",
1334+
apiModelId: "glm-5.3-flash",
13351335
}
13361336

13371337
const { result } = renderHook(() => useSelectedModel(apiConfiguration), { wrapper: createWrapper() })
13381338

1339-
expect(result.current.id).toBe("glm-5.3")
1340-
expect(result.current.info).toEqual(getZAiModels("international_coding")["glm-5.3"])
1339+
expect(result.current.id).toBe("glm-5.3-flash")
1340+
expect(result.current.info).toEqual(getZAiModels("international_coding")["glm-5.3-flash"])
1341+
expect(result.current.info?.supportsImages).toBe(true)
13411342
})
13421343

13431344
it("uses the China Coding catalog for GLM-5.3", () => {

0 commit comments

Comments
 (0)