mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-17 09:02:08 +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))
|
- 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.3] - 2026-01-13
|
||||||
|
|
||||||
## [0.45.2] - 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)
|
supportsDeveloperRole?: boolean; // Whether provider supports `developer` role vs `system` (default: true)
|
||||||
supportsReasoningEffort?: boolean; // Whether provider supports `reasoning_effort` (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)
|
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: {
|
compat: {
|
||||||
supportsDeveloperRole: false,
|
supportsDeveloperRole: false,
|
||||||
|
thinkingFormat: "zai",
|
||||||
},
|
},
|
||||||
contextWindow: m.limit?.context || 4096,
|
contextWindow: m.limit?.context || 4096,
|
||||||
maxTokens: m.limit?.output || 4096,
|
maxTokens: m.limit?.output || 4096,
|
||||||
|
|
|
||||||
|
|
@ -10733,7 +10733,7 @@ export const MODELS = {
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
provider: "zai",
|
provider: "zai",
|
||||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||||
compat: {"supportsDeveloperRole":false},
|
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
|
|
@ -10751,7 +10751,7 @@ export const MODELS = {
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
provider: "zai",
|
provider: "zai",
|
||||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||||
compat: {"supportsDeveloperRole":false},
|
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
|
|
@ -10769,7 +10769,7 @@ export const MODELS = {
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
provider: "zai",
|
provider: "zai",
|
||||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||||
compat: {"supportsDeveloperRole":false},
|
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
|
|
@ -10787,7 +10787,7 @@ export const MODELS = {
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
provider: "zai",
|
provider: "zai",
|
||||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||||
compat: {"supportsDeveloperRole":false},
|
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
|
|
@ -10805,7 +10805,7 @@ export const MODELS = {
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
provider: "zai",
|
provider: "zai",
|
||||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||||
compat: {"supportsDeveloperRole":false},
|
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
|
|
@ -10823,7 +10823,7 @@ export const MODELS = {
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
provider: "zai",
|
provider: "zai",
|
||||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||||
compat: {"supportsDeveloperRole":false},
|
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text", "image"],
|
input: ["text", "image"],
|
||||||
cost: {
|
cost: {
|
||||||
|
|
@ -10841,7 +10841,7 @@ export const MODELS = {
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
provider: "zai",
|
provider: "zai",
|
||||||
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
baseUrl: "https://api.z.ai/api/coding/paas/v4",
|
||||||
compat: {"supportsDeveloperRole":false},
|
compat: {"supportsDeveloperRole":false,"thinkingFormat":"zai"},
|
||||||
reasoning: true,
|
reasoning: true,
|
||||||
input: ["text"],
|
input: ["text"],
|
||||||
cost: {
|
cost: {
|
||||||
|
|
|
||||||
|
|
@ -404,7 +404,12 @@ function buildParams(model: Model<"openai-completions">, context: Context, optio
|
||||||
params.tool_choice = options.toolChoice;
|
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;
|
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.
|
* Returns a fully resolved OpenAICompat object with all fields set.
|
||||||
*/
|
*/
|
||||||
function detectCompatFromUrl(baseUrl: string): Required<OpenAICompat> {
|
function detectCompatFromUrl(baseUrl: string): Required<OpenAICompat> {
|
||||||
|
const isZai = baseUrl.includes("api.z.ai");
|
||||||
|
|
||||||
const isNonStandard =
|
const isNonStandard =
|
||||||
baseUrl.includes("cerebras.ai") ||
|
baseUrl.includes("cerebras.ai") ||
|
||||||
baseUrl.includes("api.x.ai") ||
|
baseUrl.includes("api.x.ai") ||
|
||||||
baseUrl.includes("mistral.ai") ||
|
baseUrl.includes("mistral.ai") ||
|
||||||
baseUrl.includes("chutes.ai");
|
baseUrl.includes("chutes.ai") ||
|
||||||
|
isZai;
|
||||||
|
|
||||||
const useMaxTokens = baseUrl.includes("mistral.ai") || baseUrl.includes("chutes.ai");
|
const useMaxTokens = baseUrl.includes("mistral.ai") || baseUrl.includes("chutes.ai");
|
||||||
|
|
||||||
|
|
@ -693,13 +701,14 @@ function detectCompatFromUrl(baseUrl: string): Required<OpenAICompat> {
|
||||||
return {
|
return {
|
||||||
supportsStore: !isNonStandard,
|
supportsStore: !isNonStandard,
|
||||||
supportsDeveloperRole: !isNonStandard,
|
supportsDeveloperRole: !isNonStandard,
|
||||||
supportsReasoningEffort: !isGrok,
|
supportsReasoningEffort: !isGrok && !isZai,
|
||||||
supportsUsageInStreaming: true,
|
supportsUsageInStreaming: true,
|
||||||
maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens",
|
maxTokensField: useMaxTokens ? "max_tokens" : "max_completion_tokens",
|
||||||
requiresToolResultName: isMistral,
|
requiresToolResultName: isMistral,
|
||||||
requiresAssistantAfterToolResult: false, // Mistral no longer requires this as of Dec 2024
|
requiresAssistantAfterToolResult: false, // Mistral no longer requires this as of Dec 2024
|
||||||
requiresThinkingAsText: isMistral,
|
requiresThinkingAsText: isMistral,
|
||||||
requiresMistralToolIds: isMistral,
|
requiresMistralToolIds: isMistral,
|
||||||
|
thinkingFormat: isZai ? "zai" : "openai",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -722,5 +731,6 @@ function getCompat(model: Model<"openai-completions">): Required<OpenAICompat> {
|
||||||
model.compat.requiresAssistantAfterToolResult ?? detected.requiresAssistantAfterToolResult,
|
model.compat.requiresAssistantAfterToolResult ?? detected.requiresAssistantAfterToolResult,
|
||||||
requiresThinkingAsText: model.compat.requiresThinkingAsText ?? detected.requiresThinkingAsText,
|
requiresThinkingAsText: model.compat.requiresThinkingAsText ?? detected.requiresThinkingAsText,
|
||||||
requiresMistralToolIds: model.compat.requiresMistralToolIds ?? detected.requiresMistralToolIds,
|
requiresMistralToolIds: model.compat.requiresMistralToolIds ?? detected.requiresMistralToolIds,
|
||||||
|
thinkingFormat: model.compat.thinkingFormat ?? detected.thinkingFormat,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,8 @@ export interface OpenAICompat {
|
||||||
requiresThinkingAsText?: boolean;
|
requiresThinkingAsText?: boolean;
|
||||||
/** Whether tool call IDs must be normalized to Mistral format (exactly 9 alphanumeric chars). Default: auto-detected from URL. */
|
/** Whether tool call IDs must be normalized to Mistral format (exactly 9 alphanumeric chars). Default: auto-detected from URL. */
|
||||||
requiresMistralToolIds?: boolean;
|
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
|
// Model interface for the unified model system
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
### Fixed
|
### 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))
|
- 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
|
## [0.45.3] - 2026-01-13
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue