fix: send anthropic thinking blocks also when thinking text is empty

fixes: #6376
This commit is contained in:
David Brailovsky 2026-07-09 15:12:34 +00:00
parent c6251a866b
commit 4b442d1b73
2 changed files with 13 additions and 5 deletions

View file

@ -1080,11 +1080,13 @@ function convertMessages(
});
continue;
}
if (block.thinking.trim().length === 0) continue;
const thinkingSignature = block.thinkingSignature;
const hasThinkingSignature = !!thinkingSignature && thinkingSignature.trim().length > 0;
if (block.thinking.trim().length === 0 && !hasThinkingSignature) continue;
// If thinking signature is missing/empty (e.g., from aborted stream),
// convert to plain text for Anthropic. Some compatible providers emit
// and accept empty signatures, so let marked models preserve the block.
if (!block.thinkingSignature || block.thinkingSignature.trim().length === 0) {
if (!hasThinkingSignature) {
blocks.push(
allowEmptySignature
? {
@ -1101,7 +1103,7 @@ function convertMessages(
blocks.push({
type: "thinking",
thinking: sanitizeSurrogates(block.thinking),
signature: block.thinkingSignature,
signature: thinkingSignature,
});
}
} else if (block.type === "toolCall") {

View file

@ -32,10 +32,10 @@ function makeModel(allowEmptySignature?: boolean): Model<"anthropic-messages"> {
};
}
function makeContext(thinkingSignature: string): Context {
function makeContext(thinkingSignature: string, thinking = "internal reasoning"): Context {
const assistant: AssistantMessage = {
role: "assistant",
content: [{ type: "thinking", thinking: "internal reasoning", thinkingSignature }],
content: [{ type: "thinking", thinking, thinkingSignature }],
provider: "xiaomi-token-plan-ams",
api: "anthropic-messages",
model: "mimo-v2.5-pro",
@ -80,6 +80,12 @@ describe("Anthropic empty thinking signature compat", () => {
expect(assistant?.content).toEqual([{ type: "text", text: "internal reasoning" }]);
});
it("preserves empty thinking text when the signature is present", async () => {
const payload = await capturePayload(makeModel(), makeContext("signed-thinking", ""));
const assistant = payload.messages?.find((message) => message.role === "assistant");
expect(assistant?.content).toEqual([{ type: "thinking", thinking: "", signature: "signed-thinking" }]);
});
it("preserves empty-signature thinking when allowEmptySignature is enabled", async () => {
const payload = await capturePayload(makeModel(true), makeContext(" "));
const assistant = payload.messages?.find((message) => message.role === "assistant");