File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change @@ -475,6 +475,34 @@ describe("ZAiHandler", () => {
475475 } )
476476
477477 describe ( "GLM-4.7 Thinking Mode" , ( ) => {
478+ it ( "should cap GLM-5.1 max_tokens to 20% of context window by default" , async ( ) => {
479+ const handlerWithModel = new ZAiHandler ( {
480+ apiModelId : "glm-5.1" ,
481+ zaiApiKey : "test-zai-api-key" ,
482+ zaiApiLine : "international_coding" ,
483+ } )
484+
485+ mockCreate . mockImplementationOnce ( ( ) => {
486+ return {
487+ [ Symbol . asyncIterator ] : ( ) => ( {
488+ async next ( ) {
489+ return { done : true }
490+ } ,
491+ } ) ,
492+ }
493+ } )
494+
495+ const messageGenerator = handlerWithModel . createMessage ( "system prompt" , [ ] )
496+ await messageGenerator . next ( )
497+
498+ expect ( mockCreate ) . toHaveBeenCalledWith (
499+ expect . objectContaining ( {
500+ model : "glm-5.1" ,
501+ max_tokens : 40_000 ,
502+ } ) ,
503+ )
504+ } )
505+
478506 it ( "should enable thinking by default for GLM-4.7 (default reasoningEffort is medium)" , async ( ) => {
479507 const handlerWithModel = new ZAiHandler ( {
480508 apiModelId : "glm-4.7" ,
Original file line number Diff line number Diff line change @@ -11,7 +11,7 @@ import {
1111 zaiApiLineConfigs ,
1212} from "@roo-code/types"
1313
14- import { type ApiHandlerOptions , shouldUseReasoningEffort } from "../../shared/api"
14+ import { type ApiHandlerOptions , getModelMaxOutputTokens , shouldUseReasoningEffort } from "../../shared/api"
1515import { convertToZAiFormat } from "../transform/zai-format"
1616
1717import type { ApiHandlerCreateMessageMetadata } from "../index"
@@ -79,11 +79,15 @@ export class ZAiHandler extends BaseOpenAiCompatibleProvider<string> {
7979 ) {
8080 const { id : model , info } = this . getModel ( )
8181
82- // Use info.maxTokens directly — Z.ai model definitions are hand-curated and accurate.
83- // getModelMaxOutputTokens clamps to 20% of contextWindow (a guard for OpenRouter dynamic
84- // metadata where maxTokens ≈ contextWindow), but ApiHandlerOptions omits apiProvider so
85- // the zai bypass in api.ts never fires. glm-5.1 legitimately supports 128k output.
86- const max_tokens = this . options . modelMaxTokens || ( info . maxTokens ?? undefined )
82+ const max_tokens =
83+ this . options . modelMaxTokens ||
84+ ( getModelMaxOutputTokens ( {
85+ modelId : model ,
86+ model : info ,
87+ settings : this . options ,
88+ format : "openai" ,
89+ } ) ??
90+ undefined )
8791
8892 const temperature = this . options . modelTemperature ?? this . defaultTemperature
8993
Original file line number Diff line number Diff line change @@ -274,8 +274,7 @@ describe("getModelMaxOutputTokens", () => {
274274 } )
275275 } )
276276
277- test ( "should bypass 20% cap for Z.ai provider and use exact configured max tokens" , ( ) => {
278- // glm-5.1: maxTokens=131_072 on a 200k context window (65.5%) — would be capped to 40k without bypass
277+ test ( "should still clamp Z.ai models to 20% of context window by default" , ( ) => {
279278 const model : ModelInfo = {
280279 contextWindow : 200_000 ,
281280 supportsPromptCache : true ,
@@ -290,7 +289,7 @@ describe("getModelMaxOutputTokens", () => {
290289 format : "openai" ,
291290 } )
292291
293- expect ( result ) . toBe ( 131_072 )
292+ expect ( result ) . toBe ( 40_000 )
294293 } )
295294
296295 test ( "should still clamp non-Z.ai models with high maxTokens to 20% of context window" , ( ) => {
Original file line number Diff line number Diff line change @@ -138,15 +138,8 @@ export const getModelMaxOutputTokens = ({
138138 // Check if this is a GPT-5 model (case-insensitive)
139139 const isGpt5Model = modelId . toLowerCase ( ) . includes ( "gpt-5" )
140140
141- // Z.ai models have hand-curated maxTokens values from Z.ai's own documentation
142- // (e.g. glm-5.1 supports 128k output on a 200k context window) — bypass the cap.
143- // Note: ZAiHandler.createStreamWithThinking bypasses this function entirely because
144- // ApiHandlerOptions omits apiProvider; this bypass serves callers that pass full
145- // ProviderSettings (Task.ts context management, model-params.ts).
146- const isZaiProvider = settings ?. apiProvider === "zai"
147-
148141 // GPT-5 models bypass the 20% cap and use their full configured max tokens
149- if ( isGpt5Model || isZaiProvider ) {
142+ if ( isGpt5Model ) {
150143 return model . maxTokens
151144 }
152145
You can’t perform that action at this time.
0 commit comments