forked from Zoo-Code-Org/Zoo-Code
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathzai.ts
More file actions
133 lines (116 loc) · 4.87 KB
/
Copy pathzai.ts
File metadata and controls
133 lines (116 loc) · 4.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
import { Anthropic } from "@anthropic-ai/sdk"
import OpenAI from "openai"
import {
internationalZAiModels,
mainlandZAiModels,
internationalZAiDefaultModelId,
mainlandZAiDefaultModelId,
type ModelInfo,
ZAI_DEFAULT_TEMPERATURE,
zaiApiLineConfigs,
} from "@roo-code/types"
import { type ApiHandlerOptions, getModelMaxOutputTokens } from "../../shared/api"
import { convertToZAiFormat } from "../transform/zai-format"
import type { ApiHandlerCreateMessageMetadata } from "../index"
import { BaseOpenAiCompatibleProvider } from "./base-openai-compatible-provider"
import { handleOpenAIError } from "./utils/openai-error-handler"
// Custom interface for Z.ai params to support thinking mode and reasoning effort tiers.
// Z.ai accepts the standard `reasoning_effort` ladder (none/minimal/low/medium/high/xhigh/max)
// alongside the GLM-specific `thinking` toggle. Omit the OpenAI-typed `reasoning_effort` so we
// can widen it to include provider-specific values such as "max".
type ZAiChatCompletionParams = Omit<OpenAI.Chat.ChatCompletionCreateParamsStreaming, "reasoning_effort"> & {
thinking?: { type: "enabled" | "disabled" }
reasoning_effort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max"
}
export class ZAiHandler extends BaseOpenAiCompatibleProvider<string> {
constructor(options: ApiHandlerOptions) {
const isChina = zaiApiLineConfigs[options.zaiApiLine ?? "international_coding"].isChina
const models = (isChina ? mainlandZAiModels : internationalZAiModels) as unknown as Record<string, ModelInfo>
const defaultModelId = (isChina ? mainlandZAiDefaultModelId : internationalZAiDefaultModelId) as string
super({
...options,
providerName: "Z.ai",
baseURL: zaiApiLineConfigs[options.zaiApiLine ?? "international_coding"].baseUrl,
apiKey: options.zaiApiKey ?? "not-provided",
defaultProviderModelId: defaultModelId,
providerModels: models,
defaultTemperature: ZAI_DEFAULT_TEMPERATURE,
})
}
/**
* Override createStream to handle GLM thinking-capable models.
* These models have thinking enabled by default in the API, so we need to
* explicitly send { type: "disabled" } when the user turns off reasoning.
*/
protected override createStream(
systemPrompt: string,
messages: Anthropic.Messages.MessageParam[],
metadata?: ApiHandlerCreateMessageMetadata,
requestOptions?: OpenAI.RequestOptions,
) {
const { id: modelId, info } = this.getModel()
// Check if this is a model with thinking support (e.g. GLM-4.7, GLM-5)
const isThinkingModel = Array.isArray(info.supportsReasoningEffort)
if (isThinkingModel) {
// Create the stream with our custom thinking parameter
return this.createStreamWithThinking(systemPrompt, messages, metadata)
}
// For non-thinking models, use the default behavior
return super.createStream(systemPrompt, messages, metadata, requestOptions)
}
/**
* Creates a stream with explicit thinking control for GLM thinking-capable models.
*/
private createStreamWithThinking(
systemPrompt: string,
messages: Anthropic.Messages.MessageParam[],
metadata?: ApiHandlerCreateMessageMetadata,
) {
const { id: model, info } = this.getModel()
// Fall back to the model default when the resolved effort isn't supported by the model.
const supported = info.supportsReasoningEffort
const raw =
this.options.enableReasoningEffort === false
? undefined
: (this.options.reasoningEffort ?? info.reasoningEffort)
const effort =
raw && raw !== "disable" && Array.isArray(supported) && !supported.includes(raw)
? info.reasoningEffort
: raw
const reasoningEffort = effort && effort !== "disable" ? effort : undefined
const useReasoning = reasoningEffort !== undefined
const max_tokens =
this.options.modelMaxTokens ||
(getModelMaxOutputTokens({
modelId: model,
model: info,
settings: this.options,
format: "openai",
}) ??
undefined)
const temperature = this.options.modelTemperature ?? this.defaultTemperature
// Use Z.ai format to preserve reasoning_content and merge post-tool text into tool messages
const convertedMessages = convertToZAiFormat(messages, { mergeToolResultText: true })
const params: ZAiChatCompletionParams = {
model,
max_tokens,
temperature,
messages: [{ role: "system", content: systemPrompt }, ...convertedMessages],
stream: true,
stream_options: { include_usage: true },
// Thinking is ON by default for these models, so explicitly disable it when needed.
thinking: useReasoning ? { type: "enabled" } : { type: "disabled" },
reasoning_effort: reasoningEffort,
tools: this.convertToolsForOpenAI(metadata?.tools),
tool_choice: metadata?.tool_choice,
parallel_tool_calls: metadata?.parallelToolCalls ?? true,
}
try {
return this.client.chat.completions.create(
params as OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming,
)
} catch (error) {
throw handleOpenAIError(error, this.providerName)
}
}
}