fix(provider): validate Base64 thought signatures and strip foreign reasoning JSON (DeepSeek/OpenAI)
This commit is contained in:
+17
-5
@@ -1871,6 +1871,15 @@ function antgWithQueue<T>(fn: () => Promise<T>): Promise<T> {
|
||||
return p;
|
||||
}
|
||||
|
||||
function isValidGeminiThoughtSignature(sig: any): sig is string {
|
||||
if (typeof sig !== "string" || !sig.trim()) return false;
|
||||
// I payload di reasoning di altri provider (es. DeepSeek / OpenAI) sono stringhe JSON come {"id":"rs_..."}
|
||||
// che Google rifiuta con errore di decodifica Base64 (TYPE_BYTES).
|
||||
if (sig.startsWith("{") || sig.startsWith("[")) return false;
|
||||
if (!/^[A-Za-z0-9+/=_-]+$/.test(sig)) return false;
|
||||
return sig.length >= 16;
|
||||
}
|
||||
|
||||
function antgBuildGeminiRequest(model: Model<Api>, context: Context, options?: SimpleStreamOptions): any {
|
||||
const contents: any[] = [];
|
||||
const push = (role: "user" | "model", part: any) => {
|
||||
@@ -1892,15 +1901,18 @@ function antgBuildGeminiRequest(model: Model<Api>, context: Context, options?: S
|
||||
const parts: any[] = [];
|
||||
for (const b of msg.content) {
|
||||
if (b.type === "text") {
|
||||
const sig = b.textSignature || (isSame ? (b as any).thoughtSignature : undefined);
|
||||
const rawSig = b.textSignature || (isSame ? (b as any).thoughtSignature : undefined);
|
||||
const sig = isValidGeminiThoughtSignature(rawSig) ? rawSig : undefined;
|
||||
if ((!b.text || !b.text.trim()) && !sig) continue;
|
||||
parts.push({ text: b.text, ...(sig ? { thoughtSignature: sig } : {}) });
|
||||
} else if (b.type === "thinking") {
|
||||
const sig = b.thinkingSignature || (isSame ? (b as any).thoughtSignature : undefined);
|
||||
const rawSig = b.thinkingSignature || (isSame ? (b as any).thoughtSignature : undefined);
|
||||
const sig = isValidGeminiThoughtSignature(rawSig) ? rawSig : undefined;
|
||||
if ((!b.thinking || !b.thinking.trim()) && !sig) continue;
|
||||
parts.push({ thought: true, text: b.thinking, ...(sig ? { thoughtSignature: sig } : {}) });
|
||||
} else if (b.type === "toolCall") {
|
||||
const sig = b.thoughtSignature || (b as any).thought_signature;
|
||||
const rawSig = b.thoughtSignature || (b as any).thought_signature;
|
||||
const sig = isValidGeminiThoughtSignature(rawSig) ? rawSig : undefined;
|
||||
if (sig) {
|
||||
if (b.id) signedToolCallIds.add(b.id);
|
||||
if (b.name) signedToolCallIds.add(b.name);
|
||||
@@ -1909,8 +1921,8 @@ function antgBuildGeminiRequest(model: Model<Api>, context: Context, options?: S
|
||||
thoughtSignature: sig,
|
||||
});
|
||||
} else {
|
||||
// Chiamata non firmata (cross-model o da provider terzo): Google Gemini 2.5/3.x
|
||||
// rigetta con HTTP 400 i functionCall privi di thought_signature.
|
||||
// Chiamata non firmata (cross-model o da provider terzo come DeepSeek): Google Gemini 2.5/3.x
|
||||
// rigetta con HTTP 400 i functionCall privi di valida Base64 thought_signature.
|
||||
// La serializziamo come testo per mantenere il contesto senza causare l'errore 400.
|
||||
parts.push({
|
||||
text: `[Tool Call: ${b.name}]\nArgs: ${JSON.stringify(b.arguments ?? {})}`,
|
||||
|
||||
Reference in New Issue
Block a user