fix(translator): correct thought signatures for AG, Gemini CLI, Vertex; fix missing Vertex response translator
- Add DEFAULT_THINKING_AG_SIGNATURE, DEFAULT_THINKING_GEMINI_CLI_SIGNATURE, DEFAULT_THINKING_VERTEX_SIGNATURE - Rename DEFAULT_THINKING_GEMINI_SIGNATURE → DEFAULT_THINKING_AG_SIGNATURE for clarity - Pass provider-specific signature into openaiToGeminiBase (AG vs Gemini CLI) - Replace synthetic thoughtSignatures with Vertex-native signature in postProcessForVertex - Register Vertex → OpenAI response translator (fixes empty Vertex streaming responses) Made-with: Cursor
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { register } from "../index.js";
|
||||
import { FORMATS } from "../formats.js";
|
||||
import { DEFAULT_THINKING_GEMINI_SIGNATURE } from "../../config/defaultThinkingSignature.js";
|
||||
import { DEFAULT_THINKING_AG_SIGNATURE, DEFAULT_THINKING_GEMINI_CLI_SIGNATURE } from "../../config/defaultThinkingSignature.js";
|
||||
import { ANTIGRAVITY_DEFAULT_SYSTEM } from "../../config/appConstants.js";
|
||||
import { openaiToClaudeRequestForAntigravity } from "./openai-to-claude.js";
|
||||
|
||||
@@ -36,7 +36,7 @@ function sanitizeGeminiFunctionName(name) {
|
||||
}
|
||||
|
||||
// Core: Convert OpenAI request to Gemini format (base for all variants)
|
||||
function openaiToGeminiBase(model, body, stream) {
|
||||
function openaiToGeminiBase(model, body, stream, signature = DEFAULT_THINKING_AG_SIGNATURE) {
|
||||
const result = {
|
||||
model: model,
|
||||
contents: [],
|
||||
@@ -109,7 +109,7 @@ function openaiToGeminiBase(model, body, stream) {
|
||||
text: msg.reasoning_content
|
||||
});
|
||||
parts.push({
|
||||
thoughtSignature: DEFAULT_THINKING_GEMINI_SIGNATURE,
|
||||
thoughtSignature: signature,
|
||||
text: ""
|
||||
});
|
||||
}
|
||||
@@ -128,7 +128,7 @@ function openaiToGeminiBase(model, body, stream) {
|
||||
|
||||
const args = tryParseJSON(tc.function?.arguments || "{}");
|
||||
parts.push({
|
||||
thoughtSignature: DEFAULT_THINKING_GEMINI_SIGNATURE,
|
||||
thoughtSignature: signature,
|
||||
functionCall: {
|
||||
id: tc.id,
|
||||
name: sanitizeGeminiFunctionName(tc.function.name),
|
||||
@@ -227,7 +227,7 @@ export function openaiToGeminiRequest(model, body, stream) {
|
||||
|
||||
// OpenAI -> Gemini CLI (Cloud Code Assist)
|
||||
export function openaiToGeminiCLIRequest(model, body, stream) {
|
||||
const gemini = openaiToGeminiBase(model, body, stream);
|
||||
const gemini = openaiToGeminiBase(model, body, stream, DEFAULT_THINKING_GEMINI_CLI_SIGNATURE);
|
||||
const isClaude = model.toLowerCase().includes("claude");
|
||||
|
||||
// Add thinking config for CLI
|
||||
|
||||
@@ -1,29 +1,25 @@
|
||||
import { register } from "../index.js";
|
||||
import { FORMATS } from "../formats.js";
|
||||
import { openaiToGeminiRequest } from "./openai-to-gemini.js";
|
||||
import { DEFAULT_THINKING_VERTEX_SIGNATURE } from "../../config/defaultThinkingSignature.js";
|
||||
|
||||
/**
|
||||
* Post-process a Gemini-format body for Vertex AI compatibility:
|
||||
*
|
||||
* 1. Strip `id` from every `functionCall` and `functionResponse` part.
|
||||
* Vertex AI rejects requests that include these fields.
|
||||
*
|
||||
* 2. Strip synthetic `thoughtSignature` parts injected by the base translator.
|
||||
* Vertex rejects fake thought signatures in multi-turn tool-call history;
|
||||
* only real signatures emitted by Vertex itself should be replayed.
|
||||
* 1. Replace all synthetic thoughtSignatures with Vertex-native signature.
|
||||
* 2. Strip `id` from functionCall and functionResponse (Vertex rejects these).
|
||||
*/
|
||||
function stripVertexIncompatibleFields(body) {
|
||||
function postProcessForVertex(body) {
|
||||
if (!body?.contents) return body;
|
||||
|
||||
for (const turn of body.contents) {
|
||||
if (!Array.isArray(turn.parts)) continue;
|
||||
|
||||
// Remove standalone synthetic thoughtSignature parts (text === "" with thoughtSignature)
|
||||
turn.parts = turn.parts.filter(
|
||||
p => !(p.thoughtSignature !== undefined && p.text === "" && !p.thought)
|
||||
);
|
||||
|
||||
for (const part of turn.parts) {
|
||||
// Replace any synthetic signature with Vertex-native one
|
||||
if (part.thoughtSignature !== undefined) {
|
||||
part.thoughtSignature = DEFAULT_THINKING_VERTEX_SIGNATURE;
|
||||
}
|
||||
// Strip id from functionCall
|
||||
if (part.functionCall && "id" in part.functionCall) {
|
||||
delete part.functionCall.id;
|
||||
@@ -32,10 +28,6 @@ function stripVertexIncompatibleFields(body) {
|
||||
if (part.functionResponse && "id" in part.functionResponse) {
|
||||
delete part.functionResponse.id;
|
||||
}
|
||||
// Strip thoughtSignature injected alongside functionCall (synthetic signature)
|
||||
if (part.functionCall && "thoughtSignature" in part) {
|
||||
delete part.thoughtSignature;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +36,7 @@ function stripVertexIncompatibleFields(body) {
|
||||
|
||||
export function openaiToVertexRequest(model, body, stream, credentials) {
|
||||
const gemini = openaiToGeminiRequest(model, body, stream, credentials);
|
||||
return stripVertexIncompatibleFields(gemini);
|
||||
return postProcessForVertex(gemini);
|
||||
}
|
||||
|
||||
register(FORMATS.OPENAI, FORMATS.VERTEX, openaiToVertexRequest, null);
|
||||
|
||||
@@ -241,4 +241,5 @@ export function geminiToOpenAIResponse(chunk, state) {
|
||||
register(FORMATS.GEMINI, FORMATS.OPENAI, null, geminiToOpenAIResponse);
|
||||
register(FORMATS.GEMINI_CLI, FORMATS.OPENAI, null, geminiToOpenAIResponse);
|
||||
register(FORMATS.ANTIGRAVITY, FORMATS.OPENAI, null, geminiToOpenAIResponse);
|
||||
register(FORMATS.VERTEX, FORMATS.OPENAI, null, geminiToOpenAIResponse);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user