Fix Anthropic empty thinking signature replay

closes #4464
This commit is contained in:
Mario Zechner
2026-05-28 12:02:54 +02:00
parent 3e9f717445
commit 458a7bc27c
10 changed files with 252 additions and 18 deletions

View File

@@ -177,6 +177,7 @@ function getAnthropicCompat(
sendSessionAffinityHeaders:
model.compat?.sendSessionAffinityHeaders ?? !!(isFireworks || isCloudflareAiGatewayAnthropic),
supportsCacheControlOnTools: model.compat?.supportsCacheControlOnTools ?? !isFireworks,
allowEmptySignature: model.compat?.allowEmptySignature ?? false,
};
}
@@ -895,7 +896,13 @@ function buildParams(
const { cacheControl } = getCacheControl(model, options?.cacheRetention);
const params: MessageCreateParamsStreaming = {
model: model.id,
messages: convertMessages(context.messages, model, isOAuthToken, cacheControl),
messages: convertMessages(
context.messages,
model,
isOAuthToken,
cacheControl,
getAnthropicCompat(model).allowEmptySignature,
),
max_tokens: options?.maxTokens ?? model.maxTokens,
stream: true,
};
@@ -1001,6 +1008,7 @@ function convertMessages(
model: Model<"anthropic-messages">,
isOAuthToken: boolean,
cacheControl?: CacheControlEphemeral,
allowEmptySignature = false,
): MessageParam[] {
const params: MessageParam[] = [];
@@ -1069,13 +1077,21 @@ function convertMessages(
}
if (block.thinking.trim().length === 0) continue;
// If thinking signature is missing/empty (e.g., from aborted stream),
// convert to plain text block without <thinking> tags to avoid API rejection
// and prevent Claude from mimicking the tags in responses
// 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) {
blocks.push({
type: "text",
text: sanitizeSurrogates(block.thinking),
});
blocks.push(
allowEmptySignature
? {
type: "thinking",
thinking: sanitizeSurrogates(block.thinking),
signature: "",
}
: {
type: "text",
text: sanitizeSurrogates(block.thinking),
},
);
} else {
blocks.push({
type: "thinking",