fix duplicated thinking tokens in chutes (#443)

Co-authored-by: xes garcia <xes.garcia@deus.ai>
This commit is contained in:
butelo 2026-01-04 18:12:09 +01:00 committed by GitHub
parent 0d477d39f9
commit 36e774282d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 30 additions and 19 deletions

View file

@ -46,6 +46,7 @@
### Fixed ### Fixed
- **OpenAI completions empty content blocks**: Empty text or thinking blocks in assistant messages are now filtered out before sending to the OpenAI completions API, preventing validation errors. ([#344](https://github.com/badlogic/pi-mono/pull/344) by [@default-anton](https://github.com/default-anton)) - **OpenAI completions empty content blocks**: Empty text or thinking blocks in assistant messages are now filtered out before sending to the OpenAI completions API, preventing validation errors. ([#344](https://github.com/badlogic/pi-mono/pull/344) by [@default-anton](https://github.com/default-anton))
- **Thinking token duplication**: Fixed thinking content duplication with chutes.ai provider. The provider was returning thinking content in both `reasoning_content` and `reasoning` fields, causing each chunk to be processed twice. Now only the first non-empty reasoning field is used.
- **zAi provider API mapping**: Fixed zAi models to use `openai-completions` API with correct base URL (`https://api.z.ai/api/coding/paas/v4`) instead of incorrect Anthropic API mapping. ([#344](https://github.com/badlogic/pi-mono/pull/344), [#358](https://github.com/badlogic/pi-mono/pull/358) by [@default-anton](https://github.com/default-anton)) - **zAi provider API mapping**: Fixed zAi models to use `openai-completions` API with correct base URL (`https://api.z.ai/api/coding/paas/v4`) instead of incorrect Anthropic API mapping. ([#344](https://github.com/badlogic/pi-mono/pull/344), [#358](https://github.com/badlogic/pi-mono/pull/358) by [@default-anton](https://github.com/default-anton))
## [0.28.0] - 2025-12-25 ## [0.28.0] - 2025-12-25

View file

@ -196,26 +196,37 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions"> = (
// Some endpoints return reasoning in reasoning_content (llama.cpp), // Some endpoints return reasoning in reasoning_content (llama.cpp),
// or reasoning (other openai compatible endpoints) // or reasoning (other openai compatible endpoints)
// Use the first non-empty reasoning field to avoid duplication
// (e.g., chutes.ai returns both reasoning_content and reasoning with same content)
const reasoningFields = ["reasoning_content", "reasoning", "reasoning_text"]; const reasoningFields = ["reasoning_content", "reasoning", "reasoning_text"];
let foundReasoningField: string | null = null;
for (const field of reasoningFields) { for (const field of reasoningFields) {
if ( if (
(choice.delta as any)[field] !== null && (choice.delta as any)[field] !== null &&
(choice.delta as any)[field] !== undefined && (choice.delta as any)[field] !== undefined &&
(choice.delta as any)[field].length > 0 (choice.delta as any)[field].length > 0
) { ) {
if (!foundReasoningField) {
foundReasoningField = field;
break;
}
}
}
if (foundReasoningField) {
if (!currentBlock || currentBlock.type !== "thinking") { if (!currentBlock || currentBlock.type !== "thinking") {
finishCurrentBlock(currentBlock); finishCurrentBlock(currentBlock);
currentBlock = { currentBlock = {
type: "thinking", type: "thinking",
thinking: "", thinking: "",
thinkingSignature: field, thinkingSignature: foundReasoningField,
}; };
output.content.push(currentBlock); output.content.push(currentBlock);
stream.push({ type: "thinking_start", contentIndex: blockIndex(), partial: output }); stream.push({ type: "thinking_start", contentIndex: blockIndex(), partial: output });
} }
if (currentBlock.type === "thinking") { if (currentBlock.type === "thinking") {
const delta = (choice.delta as any)[field]; const delta = (choice.delta as any)[foundReasoningField];
currentBlock.thinking += delta; currentBlock.thinking += delta;
stream.push({ stream.push({
type: "thinking_delta", type: "thinking_delta",
@ -225,7 +236,6 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions"> = (
}); });
} }
} }
}
if (choice?.delta?.tool_calls) { if (choice?.delta?.tool_calls) {
for (const toolCall of choice.delta.tool_calls) { for (const toolCall of choice.delta.tool_calls) {