mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-16 17:01:02 +00:00
Fix z.ai thinking/reasoning params, fixes #688
Z.ai uses thinking: { type: "enabled" | "disabled" } instead of
OpenAI's reasoning_effort. Added thinkingFormat compat flag to handle
this. Thinking is now explicitly enabled/disabled based on user setting.
This commit is contained in:
parent
00ba005e50
commit
09d409cc92
7 changed files with 29 additions and 10 deletions
|
|
@ -6,6 +6,10 @@
|
|||
|
||||
- Added Vercel AI Gateway provider with model discovery and `AI_GATEWAY_API_KEY` env support ([#689](https://github.com/badlogic/pi-mono/pull/689) by [@timolins](https://github.com/timolins))
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed z.ai thinking/reasoning: z.ai uses `thinking: { type: "enabled" }` instead of OpenAI's `reasoning_effort`. Added `thinkingFormat` compat flag to handle this. ([#688](https://github.com/badlogic/pi-mono/issues/688))
|
||||
|
||||
## [0.45.3] - 2026-01-13
|
||||
|
||||
## [0.45.2] - 2026-01-13
|
||||
|
|
|
|||
|
|
@ -711,6 +711,7 @@ interface OpenAICompat {
|
|||
supportsDeveloperRole?: boolean; // Whether provider supports `developer` role vs `system` (default: true)
|
||||
supportsReasoningEffort?: boolean; // Whether provider supports `reasoning_effort` (default: true)
|
||||
maxTokensField?: 'max_completion_tokens' | 'max_tokens'; // Which field name to use (default: max_completion_tokens)
|
||||
thinkingFormat?: 'openai' | 'zai'; // Format for reasoning param: 'openai' uses reasoning_effort, 'zai' uses thinking: { type: "enabled" } (default: openai)
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -440,6 +440,7 @@ async function loadModelsDevData(): Promise<Model<any>[]> {
|
|||
},
|
||||
compat: {
|
||||
supportsDeveloperRole: false,
|
||||
thinkingFormat: "zai",
|
||||
},
|
||||
contextWindow: m.limit?.context || 4096,
|
||||
maxTokens: m.limit?.output || 4096,
|
||||
|
|
|
|||
|
|
@ -10733,7 +10733,7 @@ export const MODELS = {
|
|||
api: "openai-completions",
|
||||
provider: "zai",
|
||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||
compat: {"supportsDeveloperRole":false},
|
||||
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
|
|
@ -10751,7 +10751,7 @@ export const MODELS = {
|
|||
api: "openai-completions",
|
||||
provider: "zai",
|
||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||
compat: {"supportsDeveloperRole":false},
|
||||
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
|
|
@ -10769,7 +10769,7 @@ export const MODELS = {
|
|||
api: "openai-completions",
|
||||
provider: "zai",
|
||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||
compat: {"supportsDeveloperRole":false},
|
||||
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
|
|
@ -10787,7 +10787,7 @@ export const MODELS = {
|
|||
api: "openai-completions",
|
||||
provider: "zai",
|
||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||
compat: {"supportsDeveloperRole":false},
|
||||
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
|
|
@ -10805,7 +10805,7 @@ export const MODELS = {
|
|||
api: "openai-completions",
|
||||
provider: "zai",
|
||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||
compat: {"supportsDeveloperRole":false},
|
||||
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
|
|
@ -10823,7 +10823,7 @@ export const MODELS = {
|
|||
api: "openai-completions",
|
||||
provider: "zai",
|
||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||
compat: {"supportsDeveloperRole":false},
|
||||
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||
reasoning: true,
|
||||
input: ["text", "image"],
|
||||
cost: {
|
||||
|
|
@ -10841,7 +10841,7 @@ export const MODELS = {
|
|||
api: "openai-completions",
|
||||
provider: "zai",
|
||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||
compat: {"supportsDeveloperRole":false},
|
||||
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: {
|
||||
|
|
|
|||
|
|
@ -404,7 +404,12 @@ function buildParams(model: Model<"openai-completions">, context: Context, optio
|
|||
params.tool_choice = options.toolChoice;
|
||||
}
|
||||
|
||||
if (options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {
|
||||
if (compat.thinkingFormat === "zai" && model.reasoning) {
|
||||
// Z.ai uses binary thinking: { type: "enabled" | "disabled" }
|
||||
// Must explicitly disable since z.ai defaults to thinking enabled
|
||||
(params as any).thinking = { type: options?.reasoningEffort ? "enabled" : "disabled" };
|
||||
} else if (options?.reasoningEffort && model.reasoning && compat.supportsReasoningEffort) {
|
||||
// OpenAI-style reasoning_effort
|
||||
params.reasoning_effort = options.reasoningEffort;
|
||||
}
|
||||
|
||||
|
|
@ -678,11 +683,14 @@ function mapStopReason(reason: ChatCompletionChunk.Choice["finish_reason"]): Sto
|
|||
* Returns a fully resolved OpenAICompat object with all fields set.
|
||||
*/
|
||||
function detectCompatFromUrl(baseUrl: string): Required<OpenAICompat> {
|
||||
const isZai = baseUrl.includes("api.z.ai");
|
||||
|
||||
const isNonStandard =
|
||||
baseUrl.includes("cerebras.ai") ||
|
||||
baseUrl.includes("api.x.ai") ||
|
||||
baseUrl.includes("mistral.ai") ||
|
||||
baseUrl.includes("chutes.ai");
|
||||
baseUrl.includes("chutes.ai") ||
|
||||
isZai;
|
||||
|
||||
const useMaxTokens = baseUrl.includes("mistral.ai") || baseUrl.includes("chutes.ai");
|
||||
|
||||
|
|
@ -693,13 +701,14 @@ function detectCompatFromUrl(baseUrl: string): Required<OpenAICompat> {
|
|||
return {
|
||||
supportsStore: !isNonStandard,
|
||||
supportsDeveloperRole: !isNonStandard,
|
||||
supportsReasoningEffort: !isGrok,
|
||||
supportsReasoningEffort: !isGrok && !isZai,
|
||||
supportsUsageInStreaming: true,
|
||||
maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens",
|
||||
requiresToolResultName: isMistral,
|
||||
requiresAssistantAfterToolResult: false, // Mistral no longer requires this as of Dec 2024
|
||||
requiresThinkingAsText: isMistral,
|
||||
requiresMistralToolIds: isMistral,
|
||||
thinkingFormat: isZai ? "zai" : "openai",
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -722,5 +731,6 @@ function getCompat(model: Model<"openai-completions">): Required<OpenAICompat> {
|
|||
model.compat.requiresAssistantAfterToolResult ?? detected.requiresAssistantAfterToolResult,
|
||||
requiresThinkingAsText: model.compat.requiresThinkingAsText ?? detected.requiresThinkingAsText,
|
||||
requiresMistralToolIds: model.compat.requiresMistralToolIds ?? detected.requiresMistralToolIds,
|
||||
thinkingFormat: model.compat.thinkingFormat ?? detected.thinkingFormat,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,6 +225,8 @@ export interface OpenAICompat {
|
|||
requiresThinkingAsText?: boolean;
|
||||
/** Whether tool call IDs must be normalized to Mistral format (exactly 9 alphanumeric chars). Default: auto-detected from URL. */
|
||||
requiresMistralToolIds?: boolean;
|
||||
/** Format for reasoning/thinking parameter. "openai" uses reasoning_effort, "zai" uses thinking: { type: "enabled" }. Default: "openai". */
|
||||
thinkingFormat?: "openai" | "zai";
|
||||
}
|
||||
|
||||
// Model interface for the unified model system
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
### Fixed
|
||||
|
||||
- Fix API key resolution after model switches by using provider argument ([#691](https://github.com/badlogic/pi-mono/pull/691) by [@joshp123](https://github.com/joshp123))
|
||||
- Fixed z.ai thinking/reasoning: thinking toggle now correctly enables/disables thinking for z.ai models ([#688](https://github.com/badlogic/pi-mono/issues/688))
|
||||
|
||||
## [0.45.3] - 2026-01-13
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue