Fix Bug
This commit is contained in:
parent
abbf8ec86f
commit
e6299eef56
6 changed files with 241 additions and 5 deletions
|
|
@ -62,6 +62,34 @@ export const CLIENT_METADATA = {
|
|||
// Internal anti-loop header
|
||||
export const INTERNAL_REQUEST_HEADER = { name: "x-request-source", value: "local" };
|
||||
|
||||
// Prefix added to client tools when forwarding to Antigravity provider (anti-ban cloaking)
|
||||
export const AG_TOOL_PREFIX = "ide_";
|
||||
|
||||
// AG native default tools — kept as decoys with neutral description/properties
|
||||
// These names must match exactly what AG sends in the real request log
|
||||
export const AG_DEFAULT_TOOLS = new Set([
|
||||
"browser_subagent",
|
||||
"command_status",
|
||||
"find_by_name",
|
||||
"generate_image",
|
||||
"grep_search",
|
||||
"list_dir",
|
||||
"list_resources",
|
||||
"multi_replace_file_content",
|
||||
"notify_user",
|
||||
"read_resource",
|
||||
"read_terminal",
|
||||
"read_url_content",
|
||||
"replace_file_content",
|
||||
"run_command",
|
||||
"search_web",
|
||||
"send_command_input",
|
||||
"task_boundary",
|
||||
"view_content_chunk",
|
||||
"view_file",
|
||||
"write_to_file"
|
||||
]);
|
||||
|
||||
// Antigravity chat/stream headers
|
||||
export const ANTIGRAVITY_HEADERS = {
|
||||
"User-Agent": `antigravity/1.107.0 ${platform()}/${arch()}`
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import crypto from "crypto";
|
||||
import { BaseExecutor } from "./base.js";
|
||||
import { PROVIDERS } from "../config/providers.js";
|
||||
import { OAUTH_ENDPOINTS, ANTIGRAVITY_HEADERS, INTERNAL_REQUEST_HEADER } from "../config/appConstants.js";
|
||||
import { OAUTH_ENDPOINTS, ANTIGRAVITY_HEADERS, INTERNAL_REQUEST_HEADER, AG_DEFAULT_TOOLS, AG_TOOL_PREFIX } from "../config/appConstants.js";
|
||||
import { HTTP_STATUS } from "../config/runtimeConfig.js";
|
||||
import { deriveSessionId } from "../utils/sessionManager.js";
|
||||
import { proxyAwareFetch } from "../utils/proxyFetch.js";
|
||||
|
|
@ -256,6 +256,197 @@ export class AntigravityExecutor extends BaseExecutor {
|
|||
|
||||
throw lastError || new Error(`All ${fallbackCount} URLs failed with status ${lastStatus}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cloak tools before sending to Antigravity provider (anti-ban):
|
||||
* - Rename client tools with ide_ prefix
|
||||
* - Inject AG default decoy tools (same names, neutral description/properties)
|
||||
* Returns { cloakedBody, toolNameMap } where toolNameMap maps prefixed → original
|
||||
*/
|
||||
static cloakTools(body) {
|
||||
const tools = body.request?.tools;
|
||||
if (!tools || tools.length === 0) {
|
||||
return { cloakedBody: body, toolNameMap: null };
|
||||
}
|
||||
|
||||
const toolNameMap = new Map();
|
||||
const allDeclarations = [];
|
||||
|
||||
// First: add AG decoy tools (to appear first in the list)
|
||||
allDeclarations.push(...AG_DECOY_TOOLS);
|
||||
|
||||
// Second: add renamed client tools
|
||||
for (const toolGroup of tools) {
|
||||
if (!toolGroup.functionDeclarations) continue;
|
||||
|
||||
for (const func of toolGroup.functionDeclarations) {
|
||||
// Skip if already an AG default tool name
|
||||
if (AG_DEFAULT_TOOLS.has(func.name)) {
|
||||
allDeclarations.push(func);
|
||||
continue;
|
||||
}
|
||||
|
||||
const prefixed = `${AG_TOOL_PREFIX}${func.name}`;
|
||||
toolNameMap.set(prefixed, func.name);
|
||||
allDeclarations.push({ ...func, name: prefixed });
|
||||
}
|
||||
}
|
||||
|
||||
// Rename tool names in conversation history (contents)
|
||||
const cloakedContents = body.request?.contents?.map(msg => {
|
||||
if (!msg.parts) return msg;
|
||||
|
||||
const cloakedParts = msg.parts.map(part => {
|
||||
// Rename functionCall.name
|
||||
if (part.functionCall && !AG_DEFAULT_TOOLS.has(part.functionCall.name)) {
|
||||
return {
|
||||
...part,
|
||||
functionCall: {
|
||||
...part.functionCall,
|
||||
name: `${AG_TOOL_PREFIX}${part.functionCall.name}`
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// Rename functionResponse.name
|
||||
if (part.functionResponse && !AG_DEFAULT_TOOLS.has(part.functionResponse.name)) {
|
||||
return {
|
||||
...part,
|
||||
functionResponse: {
|
||||
...part.functionResponse,
|
||||
name: `${AG_TOOL_PREFIX}${part.functionResponse.name}`
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return part;
|
||||
});
|
||||
|
||||
return { ...msg, parts: cloakedParts };
|
||||
});
|
||||
|
||||
// Single functionDeclarations group with decoys first, then renamed client tools
|
||||
return {
|
||||
cloakedBody: {
|
||||
...body,
|
||||
request: {
|
||||
...body.request,
|
||||
tools: [{ functionDeclarations: allDeclarations }],
|
||||
contents: cloakedContents || body.request.contents
|
||||
}
|
||||
},
|
||||
toolNameMap
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// AG decoy tools — same names as AG native defaults, neutral description & minimal properties
|
||||
const AG_DECOY_TOOLS = [
|
||||
{
|
||||
name: "browser_subagent",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "command_status",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "find_by_name",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "generate_image",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "grep_search",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "list_dir",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "list_resources",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "mcp_sequential-thinking_sequentialthinking",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "multi_replace_file_content",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "notify_user",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "read_resource",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "read_terminal",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "read_url_content",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "replace_file_content",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "run_command",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "search_web",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "send_command_input",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "task_boundary",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "view_content_chunk",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "view_file",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
},
|
||||
{
|
||||
name: "write_to_file",
|
||||
description: "This tool is not available in the current context.",
|
||||
parameters: { type: "OBJECT", properties: {}, required: [] }
|
||||
}
|
||||
];
|
||||
|
||||
export default AntigravityExecutor;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { ensureToolCallIds, fixMissingToolResponses } from "./helpers/toolCallHe
|
|||
import { prepareClaudeRequest } from "./helpers/claudeHelper.js";
|
||||
import { filterToOpenAIFormat } from "./helpers/openaiHelper.js";
|
||||
import { normalizeThinkingConfig } from "../services/provider.js";
|
||||
import { AntigravityExecutor } from "../executors/antigravity.js";
|
||||
|
||||
// Registry for translators
|
||||
const requestRegistry = new Map();
|
||||
|
|
@ -97,6 +98,16 @@ export function translateRequest(sourceFormat, targetFormat, model, body, stream
|
|||
result = prepareClaudeRequest(result, provider, apiKey);
|
||||
}
|
||||
|
||||
// Antigravity cloaking: rename client tools + inject decoys (anti-ban)
|
||||
// Skip if client is native AG (userAgent = antigravity)
|
||||
if (provider === FORMATS.ANTIGRAVITY && body.userAgent !== FORMATS.ANTIGRAVITY) {
|
||||
const { cloakedBody, toolNameMap } = AntigravityExecutor.cloakTools(result);
|
||||
result = cloakedBody;
|
||||
if (toolNameMap?.size > 0) {
|
||||
result._toolNameMap = toolNameMap;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,9 @@ export function geminiToOpenAIResponse(chunk, state) {
|
|||
}
|
||||
|
||||
if (hasFunctionCall) {
|
||||
const fcName = part.functionCall.name;
|
||||
const rawName = part.functionCall.name;
|
||||
// Restore original tool name from mapping (AG cloaking)
|
||||
const fcName = state.toolNameMap?.get(rawName) || rawName;
|
||||
const fcArgs = part.functionCall.args || {};
|
||||
const toolCallIndex = state.functionIndex++;
|
||||
|
||||
|
|
@ -107,7 +109,9 @@ export function geminiToOpenAIResponse(chunk, state) {
|
|||
|
||||
// Function call
|
||||
if (part.functionCall) {
|
||||
const fcName = part.functionCall.name;
|
||||
const rawName = part.functionCall.name;
|
||||
// Restore original tool name from mapping (AG cloaking)
|
||||
const fcName = state.toolNameMap?.get(rawName) || rawName;
|
||||
const fcArgs = part.functionCall.args || {};
|
||||
const toolCallIndex = state.functionIndex++;
|
||||
|
||||
|
|
|
|||
|
|
@ -59,9 +59,11 @@ export function openaiToAntigravityResponse(chunk, state) {
|
|||
const accum = state._toolCallAccum[idx];
|
||||
let args = {};
|
||||
try { args = JSON.parse(accum.arguments); } catch { /* empty */ }
|
||||
// Restore original tool name if it was prefixed during cloaking
|
||||
const originalName = state.toolNameMap?.get(accum.name) || accum.name;
|
||||
parts.push({
|
||||
functionCall: {
|
||||
name: accum.name,
|
||||
name: originalName,
|
||||
args
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -240,7 +240,7 @@ export default function MitmToolCard({
|
|||
|
||||
{/* Warning below button */}
|
||||
{warning && (
|
||||
<div className="flex items-center gap-2 px-2 py-1.5 rounded text-xs bg-amber-500/10 text-amber-600 border border-amber-500/20">
|
||||
<div className="flex items-center gap-2 px-2 py-1.5 rounded text-xs text-amber-500">
|
||||
<span className="material-symbols-outlined text-[14px]">warning</span>
|
||||
<span>{warning}</span>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue