@@ -16,6 +16,7 @@ import { TagMatcher } from "../../utils/tag-matcher"
1616
1717import { convertToOpenAiMessages } from "../transform/openai-format"
1818import { convertToR1Format } from "../transform/r1-format"
19+ import { convertToZAiFormat } from "../transform/zai-format"
1920import { ApiStream , ApiStreamUsageChunk } from "../transform/stream"
2021import { getModelParams } from "../transform/model-params"
2122
@@ -24,14 +25,16 @@ import { BaseProvider } from "./base-provider"
2425import type { SingleCompletionHandler , ApiHandlerCreateMessageMetadata } from "../index"
2526import { getApiRequestTimeout } from "./utils/timeout-config"
2627import { handleOpenAIError } from "./utils/openai-error-handler"
28+ import { detectGlmModel , logGlmDetection , type GlmModelConfig } from "./utils/glm-model-detection"
2729
2830// TODO: Rename this to OpenAICompatibleHandler. Also, I think the
2931// `OpenAINativeHandler` can subclass from this, since it's obviously
3032// compatible with the OpenAI API. We can also rename it to `OpenAIHandler`.
3133export class OpenAiHandler extends BaseProvider implements SingleCompletionHandler {
3234 protected options : ApiHandlerOptions
3335 protected client : OpenAI
34- private readonly providerName = "OpenAI"
36+ private readonly providerName = "OpenAI Compatible"
37+ private glmConfig : GlmModelConfig
3538
3639 constructor ( options : ApiHandlerOptions ) {
3740 super ( )
@@ -77,6 +80,12 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
7780 timeout,
7881 } )
7982 }
83+
84+ // Detect if this is a GLM model and apply optimizations
85+ this . glmConfig = detectGlmModel ( this . options . openAiModelId )
86+ if ( this . options . openAiModelId ) {
87+ logGlmDetection ( this . providerName , this . options . openAiModelId , this . glmConfig )
88+ }
8089 }
8190
8291 override async * createMessage (
@@ -106,6 +115,10 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
106115
107116 if ( deepseekReasoner ) {
108117 convertedMessages = convertToR1Format ( [ { role : "user" , content : systemPrompt } , ...messages ] )
118+ } else if ( this . glmConfig . isGlm && this . glmConfig . mergeToolResultText ) {
119+ // For GLM models, use Z.ai format with mergeToolResultText to prevent conversation flow disruption
120+ const zaiMessages = convertToZAiFormat ( messages , { mergeToolResultText : true } )
121+ convertedMessages = [ systemMessage , ...zaiMessages ]
109122 } else {
110123 if ( modelInfo . supportsPromptCache ) {
111124 systemMessage = {
@@ -152,16 +165,37 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
152165
153166 const isGrokXAI = this . _isGrokXAI ( this . options . openAiBaseUrl )
154167
168+ // Determine temperature: use GLM default (0.6) for GLM models, DeepSeek default for DeepSeek, otherwise 0
169+ let temperature : number | undefined
170+ if ( this . options . modelTemperature !== undefined ) {
171+ temperature = this . options . modelTemperature
172+ } else if ( this . glmConfig . isGlm ) {
173+ temperature = this . glmConfig . temperature
174+ } else if ( deepseekReasoner ) {
175+ temperature = DEEP_SEEK_DEFAULT_TEMPERATURE
176+ } else {
177+ temperature = 0
178+ }
179+
180+ // For GLM models, disable parallel_tool_calls as GLM models may not support it
181+ const parallelToolCalls = this . glmConfig . isGlm && this . glmConfig . disableParallelToolCalls
182+ ? false
183+ : ( metadata ?. parallelToolCalls ?? true )
184+
185+ if ( this . glmConfig . isGlm && this . glmConfig . disableParallelToolCalls ) {
186+ console . log ( `[${ this . providerName } ] parallel_tool_calls disabled for GLM model` )
187+ }
188+
155189 const requestOptions : OpenAI . Chat . Completions . ChatCompletionCreateParamsStreaming = {
156190 model : modelId ,
157- temperature : this . options . modelTemperature ?? ( deepseekReasoner ? DEEP_SEEK_DEFAULT_TEMPERATURE : 0 ) ,
191+ temperature,
158192 messages : convertedMessages ,
159193 stream : true as const ,
160194 ...( isGrokXAI ? { } : { stream_options : { include_usage : true } } ) ,
161195 ...( reasoning && reasoning ) ,
162196 tools : this . convertToolsForOpenAI ( metadata ?. tools ) ,
163197 tool_choice : metadata ?. tool_choice ,
164- parallel_tool_calls : metadata ?. parallelToolCalls ?? true ,
198+ parallel_tool_calls : parallelToolCalls ,
165199 }
166200
167201 // Add max_tokens if needed
@@ -221,15 +255,30 @@ export class OpenAiHandler extends BaseProvider implements SingleCompletionHandl
221255 yield this . processUsageMetrics ( lastUsage , modelInfo )
222256 }
223257 } else {
258+ // Non-streaming: also apply GLM-specific settings
259+ let nonStreamingMessages
260+ if ( deepseekReasoner ) {
261+ nonStreamingMessages = convertToR1Format ( [ { role : "user" , content : systemPrompt } , ...messages ] )
262+ } else if ( this . glmConfig . isGlm && this . glmConfig . mergeToolResultText ) {
263+ // For GLM models, use Z.ai format with mergeToolResultText
264+ const zaiMessages = convertToZAiFormat ( messages , { mergeToolResultText : true } )
265+ nonStreamingMessages = [ systemMessage , ...zaiMessages ]
266+ } else {
267+ nonStreamingMessages = [ systemMessage , ...convertToOpenAiMessages ( messages ) ]
268+ }
269+
270+ // For GLM models, disable parallel_tool_calls
271+ const nonStreamingParallelToolCalls = this . glmConfig . isGlm && this . glmConfig . disableParallelToolCalls
272+ ? false
273+ : ( metadata ?. parallelToolCalls ?? true )
274+
224275 const requestOptions : OpenAI . Chat . Completions . ChatCompletionCreateParamsNonStreaming = {
225276 model : modelId ,
226- messages : deepseekReasoner
227- ? convertToR1Format ( [ { role : "user" , content : systemPrompt } , ...messages ] )
228- : [ systemMessage , ...convertToOpenAiMessages ( messages ) ] ,
277+ messages : nonStreamingMessages ,
229278 // Tools are always present (minimum ALWAYS_AVAILABLE_TOOLS)
230279 tools : this . convertToolsForOpenAI ( metadata ?. tools ) ,
231280 tool_choice : metadata ?. tool_choice ,
232- parallel_tool_calls : metadata ?. parallelToolCalls ?? true ,
281+ parallel_tool_calls : nonStreamingParallelToolCalls ,
233282 }
234283
235284 // Add max_tokens if needed
0 commit comments