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,34 +196,44 @@ 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 (!currentBlock || currentBlock.type !== "thinking") { if (!foundReasoningField) {
finishCurrentBlock(currentBlock); foundReasoningField = field;
currentBlock = { break;
type: "thinking",
thinking: "",
thinkingSignature: field,
};
output.content.push(currentBlock);
stream.push({ type: "thinking_start", contentIndex: blockIndex(), partial: output });
} }
}
}
if (currentBlock.type === "thinking") { if (foundReasoningField) {
const delta = (choice.delta as any)[field]; if (!currentBlock || currentBlock.type !== "thinking") {
currentBlock.thinking += delta; finishCurrentBlock(currentBlock);
stream.push({ currentBlock = {
type: "thinking_delta", type: "thinking",
contentIndex: blockIndex(), thinking: "",
delta, thinkingSignature: foundReasoningField,
partial: output, };
}); output.content.push(currentBlock);
} stream.push({ type: "thinking_start", contentIndex: blockIndex(), partial: output });
}
if (currentBlock.type === "thinking") {
const delta = (choice.delta as any)[foundReasoningField];
currentBlock.thinking += delta;
stream.push({
type: "thinking_delta",
contentIndex: blockIndex(),
delta,
partial: output,
});
} }
} }