antigravity-auth 1.6.0 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -41
- package/dist/cli.js +2868 -0
- package/dist/handler.js +25119 -0
- package/dist/index.js +25110 -5
- package/package.json +66 -54
- package/dist/antigravity/oauth.d.ts +0 -30
- package/dist/antigravity/oauth.js +0 -170
- package/dist/claude/login.d.ts +0 -7
- package/dist/claude/login.js +0 -480
- package/dist/claude/menu-helpers.d.ts +0 -22
- package/dist/claude/menu-helpers.js +0 -281
- package/dist/claude/proxy-manager.d.ts +0 -11
- package/dist/claude/proxy-manager.js +0 -129
- package/dist/claude/proxy.d.ts +0 -1
- package/dist/claude/proxy.js +0 -733
- package/dist/constants.d.ts +0 -138
- package/dist/constants.js +0 -216
- package/dist/hooks/auto-update-checker/cache.d.ts +0 -2
- package/dist/hooks/auto-update-checker/cache.js +0 -70
- package/dist/hooks/auto-update-checker/checker.d.ts +0 -15
- package/dist/hooks/auto-update-checker/checker.js +0 -233
- package/dist/hooks/auto-update-checker/constants.d.ts +0 -8
- package/dist/hooks/auto-update-checker/constants.js +0 -22
- package/dist/hooks/auto-update-checker/index.d.ts +0 -33
- package/dist/hooks/auto-update-checker/index.js +0 -121
- package/dist/hooks/auto-update-checker/logging.d.ts +0 -2
- package/dist/hooks/auto-update-checker/logging.js +0 -8
- package/dist/hooks/auto-update-checker/types.d.ts +0 -24
- package/dist/hooks/auto-update-checker/types.js +0 -1
- package/dist/index.d.ts +0 -6
- package/dist/opencode/hooks/auto-update-checker/cache.d.ts +0 -2
- package/dist/opencode/hooks/auto-update-checker/cache.js +0 -70
- package/dist/opencode/hooks/auto-update-checker/checker.d.ts +0 -15
- package/dist/opencode/hooks/auto-update-checker/checker.js +0 -233
- package/dist/opencode/hooks/auto-update-checker/constants.d.ts +0 -8
- package/dist/opencode/hooks/auto-update-checker/constants.js +0 -22
- package/dist/opencode/hooks/auto-update-checker/index.d.ts +0 -33
- package/dist/opencode/hooks/auto-update-checker/index.js +0 -121
- package/dist/opencode/hooks/auto-update-checker/logging.d.ts +0 -2
- package/dist/opencode/hooks/auto-update-checker/logging.js +0 -8
- package/dist/opencode/hooks/auto-update-checker/types.d.ts +0 -24
- package/dist/opencode/hooks/auto-update-checker/types.js +0 -1
- package/dist/opencode/plugin.d.ts +0 -29
- package/dist/opencode/plugin.js +0 -2954
- package/dist/plugin/accounts.d.ts +0 -173
- package/dist/plugin/accounts.js +0 -966
- package/dist/plugin/auth.d.ts +0 -20
- package/dist/plugin/auth.js +0 -44
- package/dist/plugin/cache/index.d.ts +0 -4
- package/dist/plugin/cache/index.js +0 -4
- package/dist/plugin/cache/signature-cache.d.ts +0 -110
- package/dist/plugin/cache/signature-cache.js +0 -347
- package/dist/plugin/cache.d.ts +0 -43
- package/dist/plugin/cache.js +0 -180
- package/dist/plugin/cli.d.ts +0 -26
- package/dist/plugin/cli.js +0 -126
- package/dist/plugin/config/index.d.ts +0 -15
- package/dist/plugin/config/index.js +0 -15
- package/dist/plugin/config/loader.d.ts +0 -38
- package/dist/plugin/config/loader.js +0 -150
- package/dist/plugin/config/models.d.ts +0 -26
- package/dist/plugin/config/models.js +0 -95
- package/dist/plugin/config/schema.d.ts +0 -144
- package/dist/plugin/config/schema.js +0 -458
- package/dist/plugin/config/updater.d.ts +0 -76
- package/dist/plugin/config/updater.js +0 -205
- package/dist/plugin/core/streaming/index.d.ts +0 -2
- package/dist/plugin/core/streaming/index.js +0 -2
- package/dist/plugin/core/streaming/transformer.d.ts +0 -9
- package/dist/plugin/core/streaming/transformer.js +0 -301
- package/dist/plugin/core/streaming/types.d.ts +0 -28
- package/dist/plugin/core/streaming/types.js +0 -1
- package/dist/plugin/debug.d.ts +0 -93
- package/dist/plugin/debug.js +0 -375
- package/dist/plugin/errors.d.ts +0 -27
- package/dist/plugin/errors.js +0 -41
- package/dist/plugin/fingerprint.d.ts +0 -69
- package/dist/plugin/fingerprint.js +0 -137
- package/dist/plugin/image-saver.d.ts +0 -24
- package/dist/plugin/image-saver.js +0 -78
- package/dist/plugin/logger.d.ts +0 -35
- package/dist/plugin/logger.js +0 -67
- package/dist/plugin/logging-utils.d.ts +0 -22
- package/dist/plugin/logging-utils.js +0 -91
- package/dist/plugin/project.d.ts +0 -32
- package/dist/plugin/project.js +0 -229
- package/dist/plugin/quota.d.ts +0 -34
- package/dist/plugin/quota.js +0 -261
- package/dist/plugin/recovery/constants.d.ts +0 -21
- package/dist/plugin/recovery/constants.js +0 -42
- package/dist/plugin/recovery/index.d.ts +0 -11
- package/dist/plugin/recovery/index.js +0 -11
- package/dist/plugin/recovery/storage.d.ts +0 -23
- package/dist/plugin/recovery/storage.js +0 -340
- package/dist/plugin/recovery/types.d.ts +0 -115
- package/dist/plugin/recovery/types.js +0 -6
- package/dist/plugin/recovery.d.ts +0 -60
- package/dist/plugin/recovery.js +0 -360
- package/dist/plugin/refresh-queue.d.ts +0 -99
- package/dist/plugin/refresh-queue.js +0 -235
- package/dist/plugin/request-helpers.d.ts +0 -281
- package/dist/plugin/request-helpers.js +0 -2200
- package/dist/plugin/request.d.ts +0 -110
- package/dist/plugin/request.js +0 -1489
- package/dist/plugin/rotation.d.ts +0 -182
- package/dist/plugin/rotation.js +0 -364
- package/dist/plugin/search.d.ts +0 -31
- package/dist/plugin/search.js +0 -185
- package/dist/plugin/server.d.ts +0 -22
- package/dist/plugin/server.js +0 -306
- package/dist/plugin/storage.d.ts +0 -136
- package/dist/plugin/storage.js +0 -599
- package/dist/plugin/stores/signature-store.d.ts +0 -4
- package/dist/plugin/stores/signature-store.js +0 -24
- package/dist/plugin/thinking-recovery.d.ts +0 -89
- package/dist/plugin/thinking-recovery.js +0 -289
- package/dist/plugin/token.d.ts +0 -18
- package/dist/plugin/token.js +0 -127
- package/dist/plugin/transform/claude.d.ts +0 -79
- package/dist/plugin/transform/claude.js +0 -256
- package/dist/plugin/transform/cross-model-sanitizer.d.ts +0 -34
- package/dist/plugin/transform/cross-model-sanitizer.js +0 -224
- package/dist/plugin/transform/gemini.d.ts +0 -132
- package/dist/plugin/transform/gemini.js +0 -659
- package/dist/plugin/transform/index.d.ts +0 -14
- package/dist/plugin/transform/index.js +0 -9
- package/dist/plugin/transform/model-resolver.d.ts +0 -98
- package/dist/plugin/transform/model-resolver.js +0 -320
- package/dist/plugin/transform/types.d.ts +0 -110
- package/dist/plugin/transform/types.js +0 -1
- package/dist/plugin/types.d.ts +0 -95
- package/dist/plugin/types.js +0 -1
- package/dist/plugin/ui/ansi.d.ts +0 -31
- package/dist/plugin/ui/ansi.js +0 -45
- package/dist/plugin/ui/auth-menu.d.ts +0 -47
- package/dist/plugin/ui/auth-menu.js +0 -199
- package/dist/plugin/ui/confirm.d.ts +0 -1
- package/dist/plugin/ui/confirm.js +0 -14
- package/dist/plugin/ui/select.d.ts +0 -22
- package/dist/plugin/ui/select.js +0 -243
- package/dist/plugin/version.d.ts +0 -18
- package/dist/plugin/version.js +0 -79
- package/dist/src/antigravity/oauth.d.ts +0 -30
- package/dist/src/antigravity/oauth.js +0 -170
- package/dist/src/constants.d.ts +0 -138
- package/dist/src/constants.js +0 -216
- package/dist/src/hooks/auto-update-checker/cache.d.ts +0 -2
- package/dist/src/hooks/auto-update-checker/cache.js +0 -70
- package/dist/src/hooks/auto-update-checker/checker.d.ts +0 -15
- package/dist/src/hooks/auto-update-checker/checker.js +0 -233
- package/dist/src/hooks/auto-update-checker/constants.d.ts +0 -8
- package/dist/src/hooks/auto-update-checker/constants.js +0 -22
- package/dist/src/hooks/auto-update-checker/index.d.ts +0 -33
- package/dist/src/hooks/auto-update-checker/index.js +0 -121
- package/dist/src/hooks/auto-update-checker/logging.d.ts +0 -2
- package/dist/src/hooks/auto-update-checker/logging.js +0 -8
- package/dist/src/hooks/auto-update-checker/types.d.ts +0 -24
- package/dist/src/hooks/auto-update-checker/types.js +0 -1
- package/dist/src/index.d.ts +0 -6
- package/dist/src/index.js +0 -5
- package/dist/src/plugin/accounts.d.ts +0 -173
- package/dist/src/plugin/accounts.js +0 -966
- package/dist/src/plugin/auth.d.ts +0 -20
- package/dist/src/plugin/auth.js +0 -44
- package/dist/src/plugin/cache/index.d.ts +0 -4
- package/dist/src/plugin/cache/index.js +0 -4
- package/dist/src/plugin/cache/signature-cache.d.ts +0 -110
- package/dist/src/plugin/cache/signature-cache.js +0 -347
- package/dist/src/plugin/cache.d.ts +0 -43
- package/dist/src/plugin/cache.js +0 -180
- package/dist/src/plugin/cli.d.ts +0 -26
- package/dist/src/plugin/cli.js +0 -126
- package/dist/src/plugin/config/index.d.ts +0 -15
- package/dist/src/plugin/config/index.js +0 -15
- package/dist/src/plugin/config/loader.d.ts +0 -38
- package/dist/src/plugin/config/loader.js +0 -150
- package/dist/src/plugin/config/models.d.ts +0 -26
- package/dist/src/plugin/config/models.js +0 -95
- package/dist/src/plugin/config/schema.d.ts +0 -144
- package/dist/src/plugin/config/schema.js +0 -458
- package/dist/src/plugin/config/updater.d.ts +0 -76
- package/dist/src/plugin/config/updater.js +0 -205
- package/dist/src/plugin/core/streaming/index.d.ts +0 -2
- package/dist/src/plugin/core/streaming/index.js +0 -2
- package/dist/src/plugin/core/streaming/transformer.d.ts +0 -9
- package/dist/src/plugin/core/streaming/transformer.js +0 -301
- package/dist/src/plugin/core/streaming/types.d.ts +0 -28
- package/dist/src/plugin/core/streaming/types.js +0 -1
- package/dist/src/plugin/debug.d.ts +0 -93
- package/dist/src/plugin/debug.js +0 -375
- package/dist/src/plugin/errors.d.ts +0 -27
- package/dist/src/plugin/errors.js +0 -41
- package/dist/src/plugin/fingerprint.d.ts +0 -69
- package/dist/src/plugin/fingerprint.js +0 -137
- package/dist/src/plugin/image-saver.d.ts +0 -24
- package/dist/src/plugin/image-saver.js +0 -78
- package/dist/src/plugin/logger.d.ts +0 -35
- package/dist/src/plugin/logger.js +0 -67
- package/dist/src/plugin/logging-utils.d.ts +0 -22
- package/dist/src/plugin/logging-utils.js +0 -91
- package/dist/src/plugin/project.d.ts +0 -32
- package/dist/src/plugin/project.js +0 -229
- package/dist/src/plugin/quota.d.ts +0 -34
- package/dist/src/plugin/quota.js +0 -261
- package/dist/src/plugin/recovery/constants.d.ts +0 -21
- package/dist/src/plugin/recovery/constants.js +0 -42
- package/dist/src/plugin/recovery/index.d.ts +0 -11
- package/dist/src/plugin/recovery/index.js +0 -11
- package/dist/src/plugin/recovery/storage.d.ts +0 -23
- package/dist/src/plugin/recovery/storage.js +0 -340
- package/dist/src/plugin/recovery/types.d.ts +0 -115
- package/dist/src/plugin/recovery/types.js +0 -6
- package/dist/src/plugin/recovery.d.ts +0 -60
- package/dist/src/plugin/recovery.js +0 -360
- package/dist/src/plugin/refresh-queue.d.ts +0 -99
- package/dist/src/plugin/refresh-queue.js +0 -235
- package/dist/src/plugin/request-helpers.d.ts +0 -281
- package/dist/src/plugin/request-helpers.js +0 -2200
- package/dist/src/plugin/request.d.ts +0 -110
- package/dist/src/plugin/request.js +0 -1489
- package/dist/src/plugin/rotation.d.ts +0 -182
- package/dist/src/plugin/rotation.js +0 -364
- package/dist/src/plugin/search.d.ts +0 -31
- package/dist/src/plugin/search.js +0 -185
- package/dist/src/plugin/server.d.ts +0 -22
- package/dist/src/plugin/server.js +0 -306
- package/dist/src/plugin/storage.d.ts +0 -136
- package/dist/src/plugin/storage.js +0 -599
- package/dist/src/plugin/stores/signature-store.d.ts +0 -4
- package/dist/src/plugin/stores/signature-store.js +0 -24
- package/dist/src/plugin/thinking-recovery.d.ts +0 -89
- package/dist/src/plugin/thinking-recovery.js +0 -289
- package/dist/src/plugin/token.d.ts +0 -18
- package/dist/src/plugin/token.js +0 -127
- package/dist/src/plugin/transform/claude.d.ts +0 -79
- package/dist/src/plugin/transform/claude.js +0 -256
- package/dist/src/plugin/transform/cross-model-sanitizer.d.ts +0 -34
- package/dist/src/plugin/transform/cross-model-sanitizer.js +0 -224
- package/dist/src/plugin/transform/gemini.d.ts +0 -132
- package/dist/src/plugin/transform/gemini.js +0 -659
- package/dist/src/plugin/transform/index.d.ts +0 -14
- package/dist/src/plugin/transform/index.js +0 -9
- package/dist/src/plugin/transform/model-resolver.d.ts +0 -98
- package/dist/src/plugin/transform/model-resolver.js +0 -320
- package/dist/src/plugin/transform/types.d.ts +0 -110
- package/dist/src/plugin/transform/types.js +0 -1
- package/dist/src/plugin/types.d.ts +0 -95
- package/dist/src/plugin/types.js +0 -1
- package/dist/src/plugin/ui/ansi.d.ts +0 -31
- package/dist/src/plugin/ui/ansi.js +0 -45
- package/dist/src/plugin/ui/auth-menu.d.ts +0 -47
- package/dist/src/plugin/ui/auth-menu.js +0 -199
- package/dist/src/plugin/ui/confirm.d.ts +0 -1
- package/dist/src/plugin/ui/confirm.js +0 -14
- package/dist/src/plugin/ui/select.d.ts +0 -22
- package/dist/src/plugin/ui/select.js +0 -243
- package/dist/src/plugin/version.d.ts +0 -18
- package/dist/src/plugin/version.js +0 -79
package/dist/plugin/request.js
DELETED
|
@@ -1,1489 +0,0 @@
|
|
|
1
|
-
import crypto from "node:crypto";
|
|
2
|
-
import { ANTIGRAVITY_ENDPOINT, GEMINI_CLI_ENDPOINT, GEMINI_CLI_HEADERS, EMPTY_SCHEMA_PLACEHOLDER_NAME, EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION, SKIP_THOUGHT_SIGNATURE, getRandomizedHeaders, } from "../constants";
|
|
3
|
-
import { cacheSignature, getCachedSignature } from "./cache";
|
|
4
|
-
import { getKeepThinking } from "./config";
|
|
5
|
-
import { createStreamingTransformer, transformSseLine, transformStreamingPayload, } from "./core/streaming";
|
|
6
|
-
import { defaultSignatureStore } from "./stores/signature-store";
|
|
7
|
-
import { DEBUG_MESSAGE_PREFIX, isDebugTuiEnabled, logAntigravityDebugResponse, logCacheStats, } from "./debug";
|
|
8
|
-
import { createLogger } from "./logger";
|
|
9
|
-
import { cleanJSONSchemaForAntigravity, DEFAULT_THINKING_BUDGET, deepFilterThinkingBlocks, extractThinkingConfig, extractVariantThinkingConfig, extractUsageFromSsePayload, extractUsageMetadata, fixToolResponseGrouping, validateAndFixClaudeToolPairing, applyToolPairingFixes, injectParameterSignatures, injectToolHardeningInstruction, isThinkingCapableModel, normalizeThinkingConfig, parseAntigravityApiBody, resolveThinkingConfig, rewriteAntigravityPreviewAccessError, transformThinkingParts, } from "./request-helpers";
|
|
10
|
-
import { CLAUDE_TOOL_SYSTEM_INSTRUCTION, CLAUDE_DESCRIPTION_PROMPT, ANTIGRAVITY_SYSTEM_INSTRUCTION, } from "../constants";
|
|
11
|
-
import { analyzeConversationState, closeToolLoopForThinking, needsThinkingRecovery, } from "./thinking-recovery";
|
|
12
|
-
import { sanitizeCrossModelPayloadInPlace } from "./transform/cross-model-sanitizer";
|
|
13
|
-
import { isGemini3Model, isImageGenerationModel, buildImageGenerationConfig, applyGeminiTransforms, sanitizeGeminiContents, fixGeminiToolPairing } from "./transform";
|
|
14
|
-
import { resolveModelForHeaderStyle, isClaudeModel, isClaudeThinkingModel, CLAUDE_THINKING_MAX_OUTPUT_TOKENS, } from "./transform";
|
|
15
|
-
import { detectErrorType } from "./recovery";
|
|
16
|
-
import { getSessionFingerprint, buildFingerprintHeaders } from "./fingerprint";
|
|
17
|
-
const log = createLogger("request");
|
|
18
|
-
const PLUGIN_SESSION_ID = `-${crypto.randomUUID()}`;
|
|
19
|
-
const sessionDisplayedThinkingHashes = new Set();
|
|
20
|
-
const MIN_SIGNATURE_LENGTH = 50;
|
|
21
|
-
function buildSignatureSessionKey(sessionId, model, conversationKey, projectKey) {
|
|
22
|
-
const modelKey = typeof model === "string" && model.trim() ? model.toLowerCase() : "unknown";
|
|
23
|
-
const projectPart = typeof projectKey === "string" && projectKey.trim()
|
|
24
|
-
? projectKey.trim()
|
|
25
|
-
: "default";
|
|
26
|
-
const conversationPart = typeof conversationKey === "string" && conversationKey.trim()
|
|
27
|
-
? conversationKey.trim()
|
|
28
|
-
: "default";
|
|
29
|
-
return `${sessionId}:${modelKey}:${projectPart}:${conversationPart}`;
|
|
30
|
-
}
|
|
31
|
-
function shouldCacheThinkingSignatures(model) {
|
|
32
|
-
if (typeof model !== "string")
|
|
33
|
-
return false;
|
|
34
|
-
const lower = model.toLowerCase();
|
|
35
|
-
return lower.includes("claude") || lower.includes("gemini-3");
|
|
36
|
-
}
|
|
37
|
-
function hashConversationSeed(seed) {
|
|
38
|
-
return crypto.createHash("sha256").update(seed, "utf8").digest("hex").slice(0, 16);
|
|
39
|
-
}
|
|
40
|
-
function extractTextFromContent(content) {
|
|
41
|
-
if (typeof content === "string") {
|
|
42
|
-
return content;
|
|
43
|
-
}
|
|
44
|
-
if (!Array.isArray(content)) {
|
|
45
|
-
return "";
|
|
46
|
-
}
|
|
47
|
-
for (const block of content) {
|
|
48
|
-
if (!block || typeof block !== "object") {
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
const anyBlock = block;
|
|
52
|
-
if (typeof anyBlock.text === "string") {
|
|
53
|
-
return anyBlock.text;
|
|
54
|
-
}
|
|
55
|
-
if (anyBlock.text && typeof anyBlock.text === "object" && typeof anyBlock.text.text === "string") {
|
|
56
|
-
return anyBlock.text.text;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return "";
|
|
60
|
-
}
|
|
61
|
-
function extractConversationSeedFromMessages(messages) {
|
|
62
|
-
const system = messages.find((message) => message?.role === "system");
|
|
63
|
-
const users = messages.filter((message) => message?.role === "user");
|
|
64
|
-
const firstUser = users[0];
|
|
65
|
-
const lastUser = users.length > 0 ? users[users.length - 1] : undefined;
|
|
66
|
-
const systemText = system ? extractTextFromContent(system.content) : "";
|
|
67
|
-
const userText = firstUser ? extractTextFromContent(firstUser.content) : "";
|
|
68
|
-
const fallbackUserText = !userText && lastUser ? extractTextFromContent(lastUser.content) : "";
|
|
69
|
-
return [systemText, userText || fallbackUserText].filter(Boolean).join("|");
|
|
70
|
-
}
|
|
71
|
-
function extractConversationSeedFromContents(contents) {
|
|
72
|
-
const users = contents.filter((content) => content?.role === "user");
|
|
73
|
-
const firstUser = users[0];
|
|
74
|
-
const lastUser = users.length > 0 ? users[users.length - 1] : undefined;
|
|
75
|
-
const primaryUser = firstUser && Array.isArray(firstUser.parts) ? extractTextFromContent(firstUser.parts) : "";
|
|
76
|
-
if (primaryUser) {
|
|
77
|
-
return primaryUser;
|
|
78
|
-
}
|
|
79
|
-
if (lastUser && Array.isArray(lastUser.parts)) {
|
|
80
|
-
return extractTextFromContent(lastUser.parts);
|
|
81
|
-
}
|
|
82
|
-
return "";
|
|
83
|
-
}
|
|
84
|
-
function resolveConversationKey(requestPayload) {
|
|
85
|
-
const anyPayload = requestPayload;
|
|
86
|
-
const candidates = [
|
|
87
|
-
anyPayload.conversationId,
|
|
88
|
-
anyPayload.conversation_id,
|
|
89
|
-
anyPayload.thread_id,
|
|
90
|
-
anyPayload.threadId,
|
|
91
|
-
anyPayload.chat_id,
|
|
92
|
-
anyPayload.chatId,
|
|
93
|
-
anyPayload.sessionId,
|
|
94
|
-
anyPayload.session_id,
|
|
95
|
-
anyPayload.metadata?.conversation_id,
|
|
96
|
-
anyPayload.metadata?.conversationId,
|
|
97
|
-
anyPayload.metadata?.thread_id,
|
|
98
|
-
anyPayload.metadata?.threadId,
|
|
99
|
-
];
|
|
100
|
-
for (const candidate of candidates) {
|
|
101
|
-
if (typeof candidate === "string" && candidate.trim()) {
|
|
102
|
-
return candidate.trim();
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
const systemSeed = extractTextFromContent(anyPayload.systemInstruction?.parts
|
|
106
|
-
?? anyPayload.systemInstruction
|
|
107
|
-
?? anyPayload.system
|
|
108
|
-
?? anyPayload.system_instruction);
|
|
109
|
-
const messageSeed = Array.isArray(anyPayload.messages)
|
|
110
|
-
? extractConversationSeedFromMessages(anyPayload.messages)
|
|
111
|
-
: Array.isArray(anyPayload.contents)
|
|
112
|
-
? extractConversationSeedFromContents(anyPayload.contents)
|
|
113
|
-
: "";
|
|
114
|
-
const seed = [systemSeed, messageSeed].filter(Boolean).join("|");
|
|
115
|
-
if (!seed) {
|
|
116
|
-
return undefined;
|
|
117
|
-
}
|
|
118
|
-
return `seed-${hashConversationSeed(seed)}`;
|
|
119
|
-
}
|
|
120
|
-
function resolveConversationKeyFromRequests(requestObjects) {
|
|
121
|
-
for (const req of requestObjects) {
|
|
122
|
-
const key = resolveConversationKey(req);
|
|
123
|
-
if (key) {
|
|
124
|
-
return key;
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
return undefined;
|
|
128
|
-
}
|
|
129
|
-
function resolveProjectKey(candidate, fallback) {
|
|
130
|
-
if (typeof candidate === "string" && candidate.trim()) {
|
|
131
|
-
return candidate.trim();
|
|
132
|
-
}
|
|
133
|
-
if (typeof fallback === "string" && fallback.trim()) {
|
|
134
|
-
return fallback.trim();
|
|
135
|
-
}
|
|
136
|
-
return undefined;
|
|
137
|
-
}
|
|
138
|
-
function formatDebugLinesForThinking(lines) {
|
|
139
|
-
const cleaned = lines
|
|
140
|
-
.map((line) => line.trim())
|
|
141
|
-
.filter((line) => line.length > 0)
|
|
142
|
-
.slice(-50);
|
|
143
|
-
const prelude = `[ThinkingResolution] source=debug_tui lines=${cleaned.length}`;
|
|
144
|
-
return `${DEBUG_MESSAGE_PREFIX}\n- ${prelude}\n${cleaned.map((line) => `- ${line}`).join("\n")}`;
|
|
145
|
-
}
|
|
146
|
-
function injectDebugThinking(response, debugText) {
|
|
147
|
-
if (!response || typeof response !== "object") {
|
|
148
|
-
return response;
|
|
149
|
-
}
|
|
150
|
-
const resp = response;
|
|
151
|
-
if (Array.isArray(resp.candidates) && resp.candidates.length > 0) {
|
|
152
|
-
const candidates = resp.candidates.slice();
|
|
153
|
-
const first = candidates[0];
|
|
154
|
-
if (first &&
|
|
155
|
-
typeof first === "object" &&
|
|
156
|
-
first.content &&
|
|
157
|
-
typeof first.content === "object" &&
|
|
158
|
-
Array.isArray(first.content.parts)) {
|
|
159
|
-
const parts = [{ thought: true, text: debugText }, ...first.content.parts];
|
|
160
|
-
candidates[0] = { ...first, content: { ...first.content, parts } };
|
|
161
|
-
return { ...resp, candidates };
|
|
162
|
-
}
|
|
163
|
-
return resp;
|
|
164
|
-
}
|
|
165
|
-
if (Array.isArray(resp.content)) {
|
|
166
|
-
const content = [{ type: "thinking", thinking: debugText }, ...resp.content];
|
|
167
|
-
return { ...resp, content };
|
|
168
|
-
}
|
|
169
|
-
if (!resp.reasoning_content) {
|
|
170
|
-
return { ...resp, reasoning_content: debugText };
|
|
171
|
-
}
|
|
172
|
-
return resp;
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Synthetic thinking placeholder text used when keep_thinking=true but debug mode is off.
|
|
176
|
-
* Injected via the same path as debug text (injectDebugThinking) to ensure consistent
|
|
177
|
-
* signature caching and multi-turn handling.
|
|
178
|
-
*/
|
|
179
|
-
const SYNTHETIC_THINKING_PLACEHOLDER = "[Thinking preserved]\n";
|
|
180
|
-
function stripInjectedDebugFromParts(parts) {
|
|
181
|
-
if (!Array.isArray(parts)) {
|
|
182
|
-
return parts;
|
|
183
|
-
}
|
|
184
|
-
return parts.filter((part) => {
|
|
185
|
-
if (!part || typeof part !== "object") {
|
|
186
|
-
return true;
|
|
187
|
-
}
|
|
188
|
-
const record = part;
|
|
189
|
-
const text = typeof record.text === "string"
|
|
190
|
-
? record.text
|
|
191
|
-
: typeof record.thinking === "string"
|
|
192
|
-
? record.thinking
|
|
193
|
-
: undefined;
|
|
194
|
-
if (text && (text.startsWith(DEBUG_MESSAGE_PREFIX) || text.startsWith(SYNTHETIC_THINKING_PLACEHOLDER.trim()))) {
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
return true;
|
|
198
|
-
});
|
|
199
|
-
}
|
|
200
|
-
function stripInjectedDebugFromRequestPayload(payload) {
|
|
201
|
-
const anyPayload = payload;
|
|
202
|
-
if (Array.isArray(anyPayload.contents)) {
|
|
203
|
-
anyPayload.contents = anyPayload.contents.map((content) => {
|
|
204
|
-
if (!content || typeof content !== "object") {
|
|
205
|
-
return content;
|
|
206
|
-
}
|
|
207
|
-
if (Array.isArray(content.parts)) {
|
|
208
|
-
return { ...content, parts: stripInjectedDebugFromParts(content.parts) };
|
|
209
|
-
}
|
|
210
|
-
if (Array.isArray(content.content)) {
|
|
211
|
-
return { ...content, content: stripInjectedDebugFromParts(content.content) };
|
|
212
|
-
}
|
|
213
|
-
return content;
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
if (Array.isArray(anyPayload.messages)) {
|
|
217
|
-
anyPayload.messages = anyPayload.messages.map((message) => {
|
|
218
|
-
if (!message || typeof message !== "object") {
|
|
219
|
-
return message;
|
|
220
|
-
}
|
|
221
|
-
if (Array.isArray(message.content)) {
|
|
222
|
-
return { ...message, content: stripInjectedDebugFromParts(message.content) };
|
|
223
|
-
}
|
|
224
|
-
return message;
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
function isValidRequestPart(part) {
|
|
229
|
-
if (!part || typeof part !== "object") {
|
|
230
|
-
return false;
|
|
231
|
-
}
|
|
232
|
-
const record = part;
|
|
233
|
-
return (Object.prototype.hasOwnProperty.call(record, "text") ||
|
|
234
|
-
Object.prototype.hasOwnProperty.call(record, "functionCall") ||
|
|
235
|
-
Object.prototype.hasOwnProperty.call(record, "functionResponse") ||
|
|
236
|
-
Object.prototype.hasOwnProperty.call(record, "inlineData") ||
|
|
237
|
-
Object.prototype.hasOwnProperty.call(record, "fileData") ||
|
|
238
|
-
Object.prototype.hasOwnProperty.call(record, "executableCode") ||
|
|
239
|
-
Object.prototype.hasOwnProperty.call(record, "codeExecutionResult") ||
|
|
240
|
-
Object.prototype.hasOwnProperty.call(record, "thought"));
|
|
241
|
-
}
|
|
242
|
-
function sanitizeRequestPayloadForAntigravity(payload) {
|
|
243
|
-
const anyPayload = payload;
|
|
244
|
-
if (Array.isArray(anyPayload.contents)) {
|
|
245
|
-
anyPayload.contents = anyPayload.contents
|
|
246
|
-
.map((content) => {
|
|
247
|
-
if (!content || typeof content !== "object") {
|
|
248
|
-
return null;
|
|
249
|
-
}
|
|
250
|
-
const contentRecord = content;
|
|
251
|
-
const rawParts = Array.isArray(contentRecord.parts) ? contentRecord.parts : [];
|
|
252
|
-
let foundFirstFunctionCall = false;
|
|
253
|
-
const sanitizedParts = rawParts.filter(isValidRequestPart).map((part) => {
|
|
254
|
-
if (part && typeof part === "object" && part.functionCall) {
|
|
255
|
-
let sig = part.thoughtSignature || part.thought_signature;
|
|
256
|
-
if (!foundFirstFunctionCall) {
|
|
257
|
-
foundFirstFunctionCall = true;
|
|
258
|
-
if (!sig || sig.length < MIN_SIGNATURE_LENGTH) {
|
|
259
|
-
sig = SKIP_THOUGHT_SIGNATURE;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
else {
|
|
263
|
-
sig = undefined;
|
|
264
|
-
}
|
|
265
|
-
if (sig) {
|
|
266
|
-
return { ...part, thought_signature: sig, thoughtSignature: sig };
|
|
267
|
-
}
|
|
268
|
-
const newPart = { ...part };
|
|
269
|
-
delete newPart.thoughtSignature;
|
|
270
|
-
delete newPart.thought_signature;
|
|
271
|
-
return newPart;
|
|
272
|
-
}
|
|
273
|
-
return part;
|
|
274
|
-
});
|
|
275
|
-
if (sanitizedParts.length === 0) {
|
|
276
|
-
return null;
|
|
277
|
-
}
|
|
278
|
-
return {
|
|
279
|
-
...contentRecord,
|
|
280
|
-
parts: sanitizedParts,
|
|
281
|
-
};
|
|
282
|
-
})
|
|
283
|
-
.filter((content) => content !== null);
|
|
284
|
-
}
|
|
285
|
-
const systemInstruction = anyPayload.systemInstruction;
|
|
286
|
-
if (systemInstruction && typeof systemInstruction === "object" && !Array.isArray(systemInstruction)) {
|
|
287
|
-
const sys = systemInstruction;
|
|
288
|
-
if (Array.isArray(sys.parts)) {
|
|
289
|
-
const sanitizedSystemParts = sys.parts.filter(isValidRequestPart);
|
|
290
|
-
if (sanitizedSystemParts.length > 0) {
|
|
291
|
-
sys.parts = sanitizedSystemParts;
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
delete anyPayload.systemInstruction;
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
function isGeminiToolUsePart(part) {
|
|
300
|
-
return !!(part && typeof part === "object" && (part.functionCall || part.tool_use || part.toolUse));
|
|
301
|
-
}
|
|
302
|
-
function isGeminiThinkingPart(part) {
|
|
303
|
-
return !!(part &&
|
|
304
|
-
typeof part === "object" &&
|
|
305
|
-
(part.thought === true || part.type === "thinking" || part.type === "reasoning"));
|
|
306
|
-
}
|
|
307
|
-
const SENTINEL_SIGNATURE = "skip_thought_signature_validator";
|
|
308
|
-
function getThinkingPartText(part) {
|
|
309
|
-
if (!part || typeof part !== "object") {
|
|
310
|
-
return "";
|
|
311
|
-
}
|
|
312
|
-
if (typeof part.text === "string") {
|
|
313
|
-
return part.text;
|
|
314
|
-
}
|
|
315
|
-
if (typeof part.thinking === "string") {
|
|
316
|
-
return part.thinking;
|
|
317
|
-
}
|
|
318
|
-
return "";
|
|
319
|
-
}
|
|
320
|
-
function hasCachedMatchingSignature(part, sessionId) {
|
|
321
|
-
if (!part || typeof part !== "object") {
|
|
322
|
-
return false;
|
|
323
|
-
}
|
|
324
|
-
const text = getThinkingPartText(part);
|
|
325
|
-
if (!text) {
|
|
326
|
-
return false;
|
|
327
|
-
}
|
|
328
|
-
const expectedSignature = getCachedSignature(sessionId, text);
|
|
329
|
-
if (!expectedSignature) {
|
|
330
|
-
return false;
|
|
331
|
-
}
|
|
332
|
-
if (part.thought === true) {
|
|
333
|
-
return part.thoughtSignature === expectedSignature;
|
|
334
|
-
}
|
|
335
|
-
return part.signature === expectedSignature;
|
|
336
|
-
}
|
|
337
|
-
function ensureThoughtSignature(part, sessionId) {
|
|
338
|
-
if (!part || typeof part !== "object") {
|
|
339
|
-
return part;
|
|
340
|
-
}
|
|
341
|
-
if (!sessionId) {
|
|
342
|
-
return part;
|
|
343
|
-
}
|
|
344
|
-
const text = getThinkingPartText(part);
|
|
345
|
-
if (!text) {
|
|
346
|
-
return part;
|
|
347
|
-
}
|
|
348
|
-
if (part.thought === true) {
|
|
349
|
-
return { ...part, thoughtSignature: SENTINEL_SIGNATURE };
|
|
350
|
-
}
|
|
351
|
-
if (part.type === "thinking" || part.type === "reasoning" || part.type === "redacted_thinking") {
|
|
352
|
-
return { ...part, signature: SENTINEL_SIGNATURE };
|
|
353
|
-
}
|
|
354
|
-
return part;
|
|
355
|
-
}
|
|
356
|
-
function hasSignedThinkingPart(part, sessionId) {
|
|
357
|
-
if (!part || typeof part !== "object") {
|
|
358
|
-
return false;
|
|
359
|
-
}
|
|
360
|
-
if (part.thought === true) {
|
|
361
|
-
if (part.thoughtSignature === SENTINEL_SIGNATURE || part.thoughtSignature === SKIP_THOUGHT_SIGNATURE) {
|
|
362
|
-
return true;
|
|
363
|
-
}
|
|
364
|
-
if (typeof part.thoughtSignature !== "string" || part.thoughtSignature.length < MIN_SIGNATURE_LENGTH) {
|
|
365
|
-
return false;
|
|
366
|
-
}
|
|
367
|
-
if (!sessionId) {
|
|
368
|
-
return true;
|
|
369
|
-
}
|
|
370
|
-
return hasCachedMatchingSignature(part, sessionId);
|
|
371
|
-
}
|
|
372
|
-
if (part.type === "thinking" || part.type === "reasoning" || part.type === "redacted_thinking") {
|
|
373
|
-
if (part.signature === SENTINEL_SIGNATURE || part.signature === SKIP_THOUGHT_SIGNATURE) {
|
|
374
|
-
return true;
|
|
375
|
-
}
|
|
376
|
-
if (typeof part.signature !== "string" || part.signature.length < MIN_SIGNATURE_LENGTH) {
|
|
377
|
-
return false;
|
|
378
|
-
}
|
|
379
|
-
if (!sessionId) {
|
|
380
|
-
return true;
|
|
381
|
-
}
|
|
382
|
-
return hasCachedMatchingSignature(part, sessionId);
|
|
383
|
-
}
|
|
384
|
-
return false;
|
|
385
|
-
}
|
|
386
|
-
function ensureThinkingBeforeToolUseInContents(contents, signatureSessionKey) {
|
|
387
|
-
return contents.map((content) => {
|
|
388
|
-
if (!content || typeof content !== "object" || !Array.isArray(content.parts)) {
|
|
389
|
-
return content;
|
|
390
|
-
}
|
|
391
|
-
const role = content.role;
|
|
392
|
-
if (role !== "model" && role !== "assistant") {
|
|
393
|
-
return content;
|
|
394
|
-
}
|
|
395
|
-
const parts = content.parts;
|
|
396
|
-
const hasToolUse = parts.some(isGeminiToolUsePart);
|
|
397
|
-
if (!hasToolUse) {
|
|
398
|
-
return content;
|
|
399
|
-
}
|
|
400
|
-
const thinkingParts = parts.filter(isGeminiThinkingPart).map((p) => ensureThoughtSignature(p, signatureSessionKey));
|
|
401
|
-
const otherParts = parts.filter((p) => !isGeminiThinkingPart(p));
|
|
402
|
-
const hasSignedThinking = thinkingParts.some((part) => hasSignedThinkingPart(part, signatureSessionKey));
|
|
403
|
-
if (hasSignedThinking) {
|
|
404
|
-
return { ...content, parts: [...thinkingParts, ...otherParts] };
|
|
405
|
-
}
|
|
406
|
-
const lastThinking = defaultSignatureStore.get(signatureSessionKey);
|
|
407
|
-
if (!lastThinking) {
|
|
408
|
-
// Return only tool_use parts without any thinking to avoid signature validation errors
|
|
409
|
-
log.debug("Stripping thinking from tool_use content (no valid cached signature)", { signatureSessionKey });
|
|
410
|
-
return { ...content, parts: otherParts };
|
|
411
|
-
}
|
|
412
|
-
const injected = {
|
|
413
|
-
thought: true,
|
|
414
|
-
text: lastThinking.text,
|
|
415
|
-
thoughtSignature: SENTINEL_SIGNATURE,
|
|
416
|
-
};
|
|
417
|
-
return { ...content, parts: [injected, ...otherParts] };
|
|
418
|
-
});
|
|
419
|
-
}
|
|
420
|
-
function ensureMessageThinkingSignature(block, sessionId) {
|
|
421
|
-
if (!block || typeof block !== "object") {
|
|
422
|
-
return block;
|
|
423
|
-
}
|
|
424
|
-
if (block.type !== "thinking" && block.type !== "redacted_thinking") {
|
|
425
|
-
return block;
|
|
426
|
-
}
|
|
427
|
-
const text = getThinkingPartText(block);
|
|
428
|
-
if (!text) {
|
|
429
|
-
return block;
|
|
430
|
-
}
|
|
431
|
-
if (!sessionId) {
|
|
432
|
-
return block;
|
|
433
|
-
}
|
|
434
|
-
return { ...block, signature: SKIP_THOUGHT_SIGNATURE };
|
|
435
|
-
}
|
|
436
|
-
function hasToolUseInContents(contents) {
|
|
437
|
-
return contents.some((content) => {
|
|
438
|
-
if (!content || typeof content !== "object" || !Array.isArray(content.parts)) {
|
|
439
|
-
return false;
|
|
440
|
-
}
|
|
441
|
-
return content.parts.some(isGeminiToolUsePart);
|
|
442
|
-
});
|
|
443
|
-
}
|
|
444
|
-
function hasSignedThinkingInContents(contents, sessionId) {
|
|
445
|
-
return contents.some((content) => {
|
|
446
|
-
if (!content || typeof content !== "object" || !Array.isArray(content.parts)) {
|
|
447
|
-
return false;
|
|
448
|
-
}
|
|
449
|
-
return content.parts.some((part) => hasSignedThinkingPart(part, sessionId));
|
|
450
|
-
});
|
|
451
|
-
}
|
|
452
|
-
function hasToolUseInMessages(messages) {
|
|
453
|
-
return messages.some((message) => {
|
|
454
|
-
if (!message || typeof message !== "object" || !Array.isArray(message.content)) {
|
|
455
|
-
return false;
|
|
456
|
-
}
|
|
457
|
-
return message.content.some((block) => block && typeof block === "object" && (block.type === "tool_use" || block.type === "tool_result"));
|
|
458
|
-
});
|
|
459
|
-
}
|
|
460
|
-
function hasSignedThinkingInMessages(messages, sessionId) {
|
|
461
|
-
return messages.some((message) => {
|
|
462
|
-
if (!message || typeof message !== "object" || !Array.isArray(message.content)) {
|
|
463
|
-
return false;
|
|
464
|
-
}
|
|
465
|
-
return message.content.some((block) => hasSignedThinkingPart(block, sessionId));
|
|
466
|
-
});
|
|
467
|
-
}
|
|
468
|
-
function ensureThinkingBeforeToolUseInMessages(messages, signatureSessionKey) {
|
|
469
|
-
return messages.map((message) => {
|
|
470
|
-
if (!message || typeof message !== "object" || !Array.isArray(message.content)) {
|
|
471
|
-
return message;
|
|
472
|
-
}
|
|
473
|
-
if (message.role !== "assistant") {
|
|
474
|
-
return message;
|
|
475
|
-
}
|
|
476
|
-
const blocks = message.content;
|
|
477
|
-
const hasToolUse = blocks.some((b) => b && typeof b === "object" && (b.type === "tool_use" || b.type === "tool_result"));
|
|
478
|
-
if (!hasToolUse) {
|
|
479
|
-
return message;
|
|
480
|
-
}
|
|
481
|
-
const thinkingBlocks = blocks
|
|
482
|
-
.filter((b) => b && typeof b === "object" && (b.type === "thinking" || b.type === "redacted_thinking"))
|
|
483
|
-
.map((b) => ensureMessageThinkingSignature(b, signatureSessionKey));
|
|
484
|
-
const otherBlocks = blocks.filter((b) => !(b && typeof b === "object" && (b.type === "thinking" || b.type === "redacted_thinking")));
|
|
485
|
-
const hasSignedThinking = thinkingBlocks.some((block) => hasSignedThinkingPart(block, signatureSessionKey));
|
|
486
|
-
if (hasSignedThinking) {
|
|
487
|
-
return { ...message, content: [...thinkingBlocks, ...otherBlocks] };
|
|
488
|
-
}
|
|
489
|
-
const lastThinking = defaultSignatureStore.get(signatureSessionKey);
|
|
490
|
-
if (!lastThinking) {
|
|
491
|
-
const existingThinking = thinkingBlocks[0];
|
|
492
|
-
const thinkingText = existingThinking?.thinking || existingThinking?.text || "";
|
|
493
|
-
log.debug("Injecting sentinel signature (cache miss)", { signatureSessionKey });
|
|
494
|
-
const sentinelBlock = {
|
|
495
|
-
type: "thinking",
|
|
496
|
-
thinking: thinkingText,
|
|
497
|
-
signature: SKIP_THOUGHT_SIGNATURE,
|
|
498
|
-
};
|
|
499
|
-
return { ...message, content: [sentinelBlock, ...otherBlocks] };
|
|
500
|
-
}
|
|
501
|
-
const injected = {
|
|
502
|
-
type: "thinking",
|
|
503
|
-
thinking: lastThinking.text,
|
|
504
|
-
signature: SKIP_THOUGHT_SIGNATURE,
|
|
505
|
-
};
|
|
506
|
-
return { ...message, content: [injected, ...otherBlocks] };
|
|
507
|
-
});
|
|
508
|
-
}
|
|
509
|
-
/**
|
|
510
|
-
* Gets the stable session ID for this plugin instance.
|
|
511
|
-
*/
|
|
512
|
-
export function getPluginSessionId() {
|
|
513
|
-
return PLUGIN_SESSION_ID;
|
|
514
|
-
}
|
|
515
|
-
function generateSyntheticProjectId() {
|
|
516
|
-
const adjectives = ["useful", "bright", "swift", "calm", "bold"];
|
|
517
|
-
const nouns = ["fuze", "wave", "spark", "flow", "core"];
|
|
518
|
-
const adj = adjectives[Math.floor(Math.random() * adjectives.length)];
|
|
519
|
-
const noun = nouns[Math.floor(Math.random() * nouns.length)];
|
|
520
|
-
const randomPart = crypto.randomUUID().slice(0, 5).toLowerCase();
|
|
521
|
-
return `${adj}-${noun}-${randomPart}`;
|
|
522
|
-
}
|
|
523
|
-
const STREAM_ACTION = "streamGenerateContent";
|
|
524
|
-
/**
|
|
525
|
-
* Resolve a fetch() URL from RequestInfo. OpenCode / AI SDK often calls fetch(Request, init)
|
|
526
|
-
* instead of fetch(string, init); we must inspect the URL the same way in both cases.
|
|
527
|
-
*/
|
|
528
|
-
export function requestInfoToUrlString(input) {
|
|
529
|
-
if (typeof input === "string") {
|
|
530
|
-
return input;
|
|
531
|
-
}
|
|
532
|
-
if (typeof Request !== "undefined" && input instanceof Request) {
|
|
533
|
-
return input.url;
|
|
534
|
-
}
|
|
535
|
-
if (typeof URL !== "undefined" && input instanceof URL) {
|
|
536
|
-
return input.href;
|
|
537
|
-
}
|
|
538
|
-
return null;
|
|
539
|
-
}
|
|
540
|
-
/**
|
|
541
|
-
* Detects requests headed to the Google Generative Language API (or Antigravity / Cloud Code PA)
|
|
542
|
-
* so we can intercept and rewrite them.
|
|
543
|
-
*/
|
|
544
|
-
export function isGenerativeLanguageRequest(input) {
|
|
545
|
-
const url = requestInfoToUrlString(input);
|
|
546
|
-
if (!url) {
|
|
547
|
-
return false;
|
|
548
|
-
}
|
|
549
|
-
return (url.includes("generativelanguage.googleapis.com") ||
|
|
550
|
-
url.includes("cloudcode-pa"));
|
|
551
|
-
}
|
|
552
|
-
function mergeInitFromRequest(req, init) {
|
|
553
|
-
const next = { ...(init ?? {}) };
|
|
554
|
-
next.method = init?.method ?? req.method;
|
|
555
|
-
const headers = new Headers(req.headers);
|
|
556
|
-
if (init?.headers) {
|
|
557
|
-
new Headers(init.headers).forEach((value, key) => {
|
|
558
|
-
headers.set(key, value);
|
|
559
|
-
});
|
|
560
|
-
}
|
|
561
|
-
next.headers = headers;
|
|
562
|
-
next.signal = init?.signal ?? req.signal;
|
|
563
|
-
if (init?.referrer !== undefined) {
|
|
564
|
-
next.referrer = init.referrer;
|
|
565
|
-
}
|
|
566
|
-
if (init?.referrerPolicy !== undefined) {
|
|
567
|
-
next.referrerPolicy = init.referrerPolicy;
|
|
568
|
-
}
|
|
569
|
-
if (init?.mode !== undefined) {
|
|
570
|
-
next.mode = init.mode;
|
|
571
|
-
}
|
|
572
|
-
if (init?.credentials !== undefined) {
|
|
573
|
-
next.credentials = init.credentials;
|
|
574
|
-
}
|
|
575
|
-
if (init?.cache !== undefined) {
|
|
576
|
-
next.cache = init.cache;
|
|
577
|
-
}
|
|
578
|
-
if (init?.redirect !== undefined) {
|
|
579
|
-
next.redirect = init.redirect;
|
|
580
|
-
}
|
|
581
|
-
if (init?.integrity !== undefined) {
|
|
582
|
-
next.integrity = init.integrity;
|
|
583
|
-
}
|
|
584
|
-
if (init?.keepalive !== undefined) {
|
|
585
|
-
next.keepalive = init.keepalive;
|
|
586
|
-
}
|
|
587
|
-
return next;
|
|
588
|
-
}
|
|
589
|
-
/**
|
|
590
|
-
* OpenCode / AI SDK often calls fetch(Request, init) with the JSON body on the Request only.
|
|
591
|
-
* prepareAntigravityRequest reads init.body as a string; materialize so sanitization always runs.
|
|
592
|
-
*/
|
|
593
|
-
export async function materializeGenerativeLanguageFetchInput(input, init) {
|
|
594
|
-
if (typeof Request === "undefined" || !(input instanceof Request)) {
|
|
595
|
-
return { input, init };
|
|
596
|
-
}
|
|
597
|
-
if (!isGenerativeLanguageRequest(input)) {
|
|
598
|
-
return { input, init };
|
|
599
|
-
}
|
|
600
|
-
if (init !== undefined && init.body != null) {
|
|
601
|
-
return { input, init };
|
|
602
|
-
}
|
|
603
|
-
const method = (init?.method ?? input.method ?? "GET").toUpperCase();
|
|
604
|
-
if (method === "GET" || method === "HEAD") {
|
|
605
|
-
return { input: input.url, init: mergeInitFromRequest(input, init) };
|
|
606
|
-
}
|
|
607
|
-
try {
|
|
608
|
-
const bodyText = await input.clone().text();
|
|
609
|
-
const nextInit = mergeInitFromRequest(input, init);
|
|
610
|
-
nextInit.body = bodyText;
|
|
611
|
-
return { input: input.url, init: nextInit };
|
|
612
|
-
}
|
|
613
|
-
catch {
|
|
614
|
-
return { input, init };
|
|
615
|
-
}
|
|
616
|
-
}
|
|
617
|
-
export function prepareAntigravityRequest(input, init, accessToken, projectId, endpointOverride, headerStyle = "antigravity", forceThinkingRecovery = false, options) {
|
|
618
|
-
const baseInit = { ...init };
|
|
619
|
-
const headers = new Headers(init?.headers ?? {});
|
|
620
|
-
let resolvedProjectId = projectId?.trim() || "";
|
|
621
|
-
let toolDebugMissing = 0;
|
|
622
|
-
const toolDebugSummaries = [];
|
|
623
|
-
let toolDebugPayload;
|
|
624
|
-
let sessionId;
|
|
625
|
-
let needsSignedThinkingWarmup = false;
|
|
626
|
-
let thinkingRecoveryMessage;
|
|
627
|
-
if (!isGenerativeLanguageRequest(input)) {
|
|
628
|
-
return {
|
|
629
|
-
request: input,
|
|
630
|
-
init: { ...baseInit, headers },
|
|
631
|
-
streaming: false,
|
|
632
|
-
headerStyle,
|
|
633
|
-
};
|
|
634
|
-
}
|
|
635
|
-
headers.set("Authorization", `Bearer ${accessToken}`);
|
|
636
|
-
headers.delete("x-api-key");
|
|
637
|
-
headers.delete("x-goog-user-project");
|
|
638
|
-
const inputUrl = requestInfoToUrlString(input);
|
|
639
|
-
if (!inputUrl) {
|
|
640
|
-
return {
|
|
641
|
-
request: input,
|
|
642
|
-
init: { ...baseInit, headers },
|
|
643
|
-
streaming: false,
|
|
644
|
-
headerStyle,
|
|
645
|
-
};
|
|
646
|
-
}
|
|
647
|
-
const match = inputUrl.match(/\/models\/([^:]+):(\w+)/);
|
|
648
|
-
if (!match) {
|
|
649
|
-
return {
|
|
650
|
-
request: input,
|
|
651
|
-
init: { ...baseInit, headers },
|
|
652
|
-
streaming: false,
|
|
653
|
-
headerStyle,
|
|
654
|
-
};
|
|
655
|
-
}
|
|
656
|
-
const [, rawModel = "", rawAction = ""] = match;
|
|
657
|
-
const requestedModel = rawModel;
|
|
658
|
-
const resolved = resolveModelForHeaderStyle(rawModel, headerStyle);
|
|
659
|
-
let effectiveModel = resolved.actualModel;
|
|
660
|
-
const streaming = rawAction === STREAM_ACTION;
|
|
661
|
-
const defaultEndpoint = headerStyle === "gemini-cli" ? GEMINI_CLI_ENDPOINT : ANTIGRAVITY_ENDPOINT;
|
|
662
|
-
const baseEndpoint = endpointOverride ?? defaultEndpoint;
|
|
663
|
-
const transformedUrl = `${baseEndpoint}/v1internal:${rawAction}${streaming ? "?alt=sse" : ""}`;
|
|
664
|
-
const isClaude = isClaudeModel(resolved.actualModel);
|
|
665
|
-
const isClaudeThinking = isClaudeThinkingModel(resolved.actualModel);
|
|
666
|
-
const keepThinkingEnabled = getKeepThinking();
|
|
667
|
-
const enableClaudePromptAutoCaching = options?.claudePromptAutoCaching ?? false;
|
|
668
|
-
let tierThinkingBudget = resolved.thinkingBudget;
|
|
669
|
-
let tierThinkingLevel = resolved.thinkingLevel;
|
|
670
|
-
let signatureSessionKey = buildSignatureSessionKey(PLUGIN_SESSION_ID, effectiveModel, undefined, resolveProjectKey(projectId));
|
|
671
|
-
let body = baseInit.body;
|
|
672
|
-
if (typeof baseInit.body === "string" && baseInit.body) {
|
|
673
|
-
try {
|
|
674
|
-
const parsedBody = JSON.parse(baseInit.body);
|
|
675
|
-
const isWrapped = typeof parsedBody.project === "string" && "request" in parsedBody;
|
|
676
|
-
if (isWrapped) {
|
|
677
|
-
const wrappedBody = {
|
|
678
|
-
...parsedBody,
|
|
679
|
-
model: effectiveModel,
|
|
680
|
-
};
|
|
681
|
-
// We still need to sanitize Claude thinking blocks (remove cache_control)
|
|
682
|
-
const requestRoot = wrappedBody.request;
|
|
683
|
-
const requestObjects = [];
|
|
684
|
-
if (requestRoot && typeof requestRoot === "object") {
|
|
685
|
-
requestObjects.push(requestRoot);
|
|
686
|
-
const nested = requestRoot.request;
|
|
687
|
-
if (nested && typeof nested === "object") {
|
|
688
|
-
requestObjects.push(nested);
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
const conversationKey = resolveConversationKeyFromRequests(requestObjects);
|
|
692
|
-
const modelForCacheKey = effectiveModel.replace(/-(minimal|low|medium|high)$/i, "");
|
|
693
|
-
signatureSessionKey = buildSignatureSessionKey(PLUGIN_SESSION_ID, modelForCacheKey, conversationKey, resolveProjectKey(parsedBody.project));
|
|
694
|
-
if (requestObjects.length > 0) {
|
|
695
|
-
sessionId = signatureSessionKey;
|
|
696
|
-
}
|
|
697
|
-
for (const req of requestObjects) {
|
|
698
|
-
req.sessionId = signatureSessionKey;
|
|
699
|
-
stripInjectedDebugFromRequestPayload(req);
|
|
700
|
-
if (isClaude) {
|
|
701
|
-
sanitizeCrossModelPayloadInPlace(req, { targetModel: effectiveModel });
|
|
702
|
-
deepFilterThinkingBlocks(req, signatureSessionKey, getCachedSignature, true);
|
|
703
|
-
if (enableClaudePromptAutoCaching && req.cache_control === undefined) {
|
|
704
|
-
req.cache_control = { type: "ephemeral" };
|
|
705
|
-
}
|
|
706
|
-
if (isClaudeThinking && keepThinkingEnabled && Array.isArray(req.contents)) {
|
|
707
|
-
req.contents = ensureThinkingBeforeToolUseInContents(req.contents, signatureSessionKey);
|
|
708
|
-
}
|
|
709
|
-
if (isClaudeThinking && keepThinkingEnabled && Array.isArray(req.messages)) {
|
|
710
|
-
req.messages = ensureThinkingBeforeToolUseInMessages(req.messages, signatureSessionKey);
|
|
711
|
-
}
|
|
712
|
-
applyToolPairingFixes(req, true);
|
|
713
|
-
}
|
|
714
|
-
else {
|
|
715
|
-
// OpenCode often sends an already-wrapped `{ project, request }` body. That path used to
|
|
716
|
-
sanitizeRequestPayloadForAntigravity(req);
|
|
717
|
-
if (Array.isArray(req.contents)) {
|
|
718
|
-
req.contents = sanitizeGeminiContents(req.contents);
|
|
719
|
-
req.contents = fixGeminiToolPairing(req.contents);
|
|
720
|
-
req.contents = sanitizeGeminiContents(req.contents);
|
|
721
|
-
}
|
|
722
|
-
}
|
|
723
|
-
}
|
|
724
|
-
if (isClaudeThinking && keepThinkingEnabled && sessionId) {
|
|
725
|
-
const hasToolUse = requestObjects.some((req) => (Array.isArray(req.contents) && hasToolUseInContents(req.contents)) ||
|
|
726
|
-
(Array.isArray(req.messages) && hasToolUseInMessages(req.messages)));
|
|
727
|
-
const hasSignedThinking = requestObjects.some((req) => (Array.isArray(req.contents) && hasSignedThinkingInContents(req.contents, signatureSessionKey)) ||
|
|
728
|
-
(Array.isArray(req.messages) && hasSignedThinkingInMessages(req.messages, signatureSessionKey)));
|
|
729
|
-
const hasCachedThinking = defaultSignatureStore.has(signatureSessionKey);
|
|
730
|
-
needsSignedThinkingWarmup = hasToolUse && !hasSignedThinking && !hasCachedThinking;
|
|
731
|
-
}
|
|
732
|
-
body = JSON.stringify(wrappedBody);
|
|
733
|
-
}
|
|
734
|
-
else {
|
|
735
|
-
const requestPayload = { ...parsedBody };
|
|
736
|
-
const rawGenerationConfig = requestPayload.generationConfig;
|
|
737
|
-
const extraBody = requestPayload.extra_body;
|
|
738
|
-
const variantConfig = extractVariantThinkingConfig(requestPayload.providerOptions, rawGenerationConfig);
|
|
739
|
-
const isGemini3 = effectiveModel.toLowerCase().includes("gemini-3");
|
|
740
|
-
log.debug(`[ThinkingResolution] rawModel=${rawModel} resolvedModel=${effectiveModel} resolvedTier=${tierThinkingLevel ?? "none"} variantLevel=${variantConfig?.thinkingLevel ?? "none"} variantBudget=${variantConfig?.thinkingBudget ?? "none"} providerOptions.google=${JSON.stringify(requestPayload.providerOptions?.google ?? null)} generationConfig.thinkingConfig=${JSON.stringify(rawGenerationConfig?.thinkingConfig ?? null)}`);
|
|
741
|
-
if (variantConfig?.thinkingLevel && isGemini3) {
|
|
742
|
-
tierThinkingLevel = variantConfig.thinkingLevel;
|
|
743
|
-
tierThinkingBudget = undefined;
|
|
744
|
-
}
|
|
745
|
-
else if (variantConfig?.thinkingBudget) {
|
|
746
|
-
if (isGemini3) {
|
|
747
|
-
log.warn("[Deprecated] Using thinkingBudget for Gemini 3 model. Use thinkingLevel instead.");
|
|
748
|
-
tierThinkingLevel = variantConfig.thinkingBudget <= 8192 ? "low"
|
|
749
|
-
: variantConfig.thinkingBudget <= 16384 ? "medium" : "high";
|
|
750
|
-
tierThinkingBudget = undefined;
|
|
751
|
-
}
|
|
752
|
-
else {
|
|
753
|
-
tierThinkingBudget = variantConfig.thinkingBudget;
|
|
754
|
-
tierThinkingLevel = undefined;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
if (isClaude) {
|
|
758
|
-
if (!requestPayload.toolConfig) {
|
|
759
|
-
requestPayload.toolConfig = {};
|
|
760
|
-
}
|
|
761
|
-
if (typeof requestPayload.toolConfig === "object" && requestPayload.toolConfig !== null) {
|
|
762
|
-
const toolConfig = requestPayload.toolConfig;
|
|
763
|
-
if (!toolConfig.functionCallingConfig) {
|
|
764
|
-
toolConfig.functionCallingConfig = {};
|
|
765
|
-
}
|
|
766
|
-
if (typeof toolConfig.functionCallingConfig === "object" && toolConfig.functionCallingConfig !== null) {
|
|
767
|
-
toolConfig.functionCallingConfig.mode = "VALIDATED";
|
|
768
|
-
}
|
|
769
|
-
}
|
|
770
|
-
}
|
|
771
|
-
const isImageModel = isImageGenerationModel(effectiveModel);
|
|
772
|
-
const userThinkingConfig = isImageModel ? undefined : extractThinkingConfig(requestPayload, rawGenerationConfig, extraBody);
|
|
773
|
-
const hasAssistantHistory = Array.isArray(requestPayload.contents) &&
|
|
774
|
-
requestPayload.contents.some((c) => c?.role === "model" || c?.role === "assistant");
|
|
775
|
-
const lowerEffective = effectiveModel.toLowerCase();
|
|
776
|
-
const isClaudeSonnetNonThinking = lowerEffective === "claude-sonnet-4-6";
|
|
777
|
-
const effectiveUserThinkingConfig = (isClaudeSonnetNonThinking || isImageModel) ? undefined : userThinkingConfig;
|
|
778
|
-
if (isImageModel) {
|
|
779
|
-
const imageConfig = buildImageGenerationConfig();
|
|
780
|
-
const generationConfig = (rawGenerationConfig ?? {});
|
|
781
|
-
generationConfig.imageConfig = imageConfig;
|
|
782
|
-
delete generationConfig.thinkingConfig;
|
|
783
|
-
if (!generationConfig.candidateCount) {
|
|
784
|
-
generationConfig.candidateCount = 1;
|
|
785
|
-
}
|
|
786
|
-
requestPayload.generationConfig = generationConfig;
|
|
787
|
-
if (!requestPayload.safetySettings) {
|
|
788
|
-
requestPayload.safetySettings = [
|
|
789
|
-
{ category: "HARM_CATEGORY_HARASSMENT", threshold: "BLOCK_ONLY_HIGH" },
|
|
790
|
-
{ category: "HARM_CATEGORY_HATE_SPEECH", threshold: "BLOCK_ONLY_HIGH" },
|
|
791
|
-
{ category: "HARM_CATEGORY_SEXUALLY_EXPLICIT", threshold: "BLOCK_ONLY_HIGH" },
|
|
792
|
-
{ category: "HARM_CATEGORY_DANGEROUS_CONTENT", threshold: "BLOCK_ONLY_HIGH" },
|
|
793
|
-
{ category: "HARM_CATEGORY_CIVIC_INTEGRITY", threshold: "BLOCK_ONLY_HIGH" },
|
|
794
|
-
];
|
|
795
|
-
}
|
|
796
|
-
delete requestPayload.tools;
|
|
797
|
-
delete requestPayload.toolConfig;
|
|
798
|
-
requestPayload.systemInstruction = {
|
|
799
|
-
parts: [{ text: "You are an AI image generator. Generate images based on user descriptions. Focus on creating high-quality, visually appealing images that match the user's request." }]
|
|
800
|
-
};
|
|
801
|
-
}
|
|
802
|
-
else {
|
|
803
|
-
const finalThinkingConfig = resolveThinkingConfig(effectiveUserThinkingConfig, isClaudeSonnetNonThinking ? false : (resolved.isThinkingModel ?? isThinkingCapableModel(effectiveModel)), isClaude, hasAssistantHistory);
|
|
804
|
-
const normalizedThinking = normalizeThinkingConfig(finalThinkingConfig);
|
|
805
|
-
if (normalizedThinking) {
|
|
806
|
-
const thinkingBudget = tierThinkingBudget ?? normalizedThinking.thinkingBudget;
|
|
807
|
-
let thinkingConfig;
|
|
808
|
-
if (isClaudeThinking) {
|
|
809
|
-
// Claude uses snake_case keys
|
|
810
|
-
thinkingConfig = {
|
|
811
|
-
include_thoughts: normalizedThinking.includeThoughts ?? true,
|
|
812
|
-
...(typeof thinkingBudget === "number" && thinkingBudget > 0
|
|
813
|
-
? { thinking_budget: thinkingBudget }
|
|
814
|
-
: {}),
|
|
815
|
-
};
|
|
816
|
-
}
|
|
817
|
-
else if (tierThinkingLevel) {
|
|
818
|
-
thinkingConfig = {
|
|
819
|
-
includeThoughts: normalizedThinking.includeThoughts,
|
|
820
|
-
thinkingLevel: tierThinkingLevel,
|
|
821
|
-
};
|
|
822
|
-
}
|
|
823
|
-
else {
|
|
824
|
-
thinkingConfig = {
|
|
825
|
-
includeThoughts: normalizedThinking.includeThoughts,
|
|
826
|
-
...(typeof thinkingBudget === "number" && thinkingBudget > 0 ? { thinkingBudget } : {}),
|
|
827
|
-
};
|
|
828
|
-
}
|
|
829
|
-
if (rawGenerationConfig) {
|
|
830
|
-
rawGenerationConfig.thinkingConfig = thinkingConfig;
|
|
831
|
-
if (isClaudeThinking && typeof thinkingBudget === "number" && thinkingBudget > 0) {
|
|
832
|
-
const currentMax = (rawGenerationConfig.maxOutputTokens ?? rawGenerationConfig.max_output_tokens);
|
|
833
|
-
if (!currentMax || currentMax <= thinkingBudget) {
|
|
834
|
-
rawGenerationConfig.maxOutputTokens = CLAUDE_THINKING_MAX_OUTPUT_TOKENS;
|
|
835
|
-
if (rawGenerationConfig.max_output_tokens !== undefined) {
|
|
836
|
-
delete rawGenerationConfig.max_output_tokens;
|
|
837
|
-
}
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
requestPayload.generationConfig = rawGenerationConfig;
|
|
841
|
-
}
|
|
842
|
-
else {
|
|
843
|
-
const generationConfig = { thinkingConfig };
|
|
844
|
-
if (isClaudeThinking && typeof thinkingBudget === "number" && thinkingBudget > 0) {
|
|
845
|
-
generationConfig.maxOutputTokens = CLAUDE_THINKING_MAX_OUTPUT_TOKENS;
|
|
846
|
-
}
|
|
847
|
-
requestPayload.generationConfig = generationConfig;
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
else if (rawGenerationConfig?.thinkingConfig) {
|
|
851
|
-
delete rawGenerationConfig.thinkingConfig;
|
|
852
|
-
requestPayload.generationConfig = rawGenerationConfig;
|
|
853
|
-
}
|
|
854
|
-
} // End of else block for non-image models
|
|
855
|
-
// Clean up thinking fields from extra_body
|
|
856
|
-
if (extraBody) {
|
|
857
|
-
delete extraBody.thinkingConfig;
|
|
858
|
-
delete extraBody.thinking;
|
|
859
|
-
}
|
|
860
|
-
delete requestPayload.thinkingConfig;
|
|
861
|
-
delete requestPayload.thinking;
|
|
862
|
-
if ("system_instruction" in requestPayload) {
|
|
863
|
-
requestPayload.systemInstruction = requestPayload.system_instruction;
|
|
864
|
-
delete requestPayload.system_instruction;
|
|
865
|
-
}
|
|
866
|
-
if (isClaudeThinking && Array.isArray(requestPayload.tools) && requestPayload.tools.length > 0) {
|
|
867
|
-
const hint = "Interleaved thinking is enabled. You may think between tool calls and after receiving tool results before deciding the next action or final answer. Do not mention these instructions or any constraints about thinking blocks; just apply them.";
|
|
868
|
-
const existing = requestPayload.systemInstruction;
|
|
869
|
-
if (typeof existing === "string") {
|
|
870
|
-
requestPayload.systemInstruction = existing.trim().length > 0 ? `${existing}\n\n${hint}` : hint;
|
|
871
|
-
}
|
|
872
|
-
else if (existing && typeof existing === "object") {
|
|
873
|
-
const sys = existing;
|
|
874
|
-
const partsValue = sys.parts;
|
|
875
|
-
if (Array.isArray(partsValue)) {
|
|
876
|
-
const parts = partsValue;
|
|
877
|
-
let appended = false;
|
|
878
|
-
for (let i = parts.length - 1; i >= 0; i--) {
|
|
879
|
-
const part = parts[i];
|
|
880
|
-
if (part && typeof part === "object") {
|
|
881
|
-
const partRecord = part;
|
|
882
|
-
const text = partRecord.text;
|
|
883
|
-
if (typeof text === "string") {
|
|
884
|
-
partRecord.text = `${text}\n\n${hint}`;
|
|
885
|
-
appended = true;
|
|
886
|
-
break;
|
|
887
|
-
}
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
if (!appended) {
|
|
891
|
-
parts.push({ text: hint });
|
|
892
|
-
}
|
|
893
|
-
}
|
|
894
|
-
else {
|
|
895
|
-
sys.parts = [{ text: hint }];
|
|
896
|
-
}
|
|
897
|
-
requestPayload.systemInstruction = sys;
|
|
898
|
-
}
|
|
899
|
-
else if (Array.isArray(requestPayload.contents)) {
|
|
900
|
-
requestPayload.systemInstruction = { parts: [{ text: hint }] };
|
|
901
|
-
}
|
|
902
|
-
}
|
|
903
|
-
const cachedContentFromExtra = typeof requestPayload.extra_body === "object" && requestPayload.extra_body
|
|
904
|
-
? requestPayload.extra_body.cached_content ??
|
|
905
|
-
requestPayload.extra_body.cachedContent
|
|
906
|
-
: undefined;
|
|
907
|
-
const cachedContent = requestPayload.cached_content ??
|
|
908
|
-
requestPayload.cachedContent ??
|
|
909
|
-
cachedContentFromExtra;
|
|
910
|
-
if (cachedContent) {
|
|
911
|
-
requestPayload.cachedContent = cachedContent;
|
|
912
|
-
}
|
|
913
|
-
delete requestPayload.cached_content;
|
|
914
|
-
delete requestPayload.cachedContent;
|
|
915
|
-
if (requestPayload.extra_body && typeof requestPayload.extra_body === "object") {
|
|
916
|
-
delete requestPayload.extra_body.cached_content;
|
|
917
|
-
delete requestPayload.extra_body.cachedContent;
|
|
918
|
-
if (Object.keys(requestPayload.extra_body).length === 0) {
|
|
919
|
-
delete requestPayload.extra_body;
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
const hasTools = Array.isArray(requestPayload.tools) && requestPayload.tools.length > 0;
|
|
923
|
-
if (hasTools) {
|
|
924
|
-
if (isClaude) {
|
|
925
|
-
const functionDeclarations = [];
|
|
926
|
-
const passthroughTools = [];
|
|
927
|
-
const normalizeSchema = (schema) => {
|
|
928
|
-
const createPlaceholderSchema = (base = {}) => ({
|
|
929
|
-
...base,
|
|
930
|
-
type: "object",
|
|
931
|
-
properties: {
|
|
932
|
-
[EMPTY_SCHEMA_PLACEHOLDER_NAME]: {
|
|
933
|
-
type: "boolean",
|
|
934
|
-
description: EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION,
|
|
935
|
-
},
|
|
936
|
-
},
|
|
937
|
-
required: [EMPTY_SCHEMA_PLACEHOLDER_NAME],
|
|
938
|
-
});
|
|
939
|
-
if (!schema || typeof schema !== "object" || Array.isArray(schema)) {
|
|
940
|
-
toolDebugMissing += 1;
|
|
941
|
-
return createPlaceholderSchema();
|
|
942
|
-
}
|
|
943
|
-
const cleaned = cleanJSONSchemaForAntigravity(schema);
|
|
944
|
-
if (!cleaned || typeof cleaned !== "object" || Array.isArray(cleaned)) {
|
|
945
|
-
toolDebugMissing += 1;
|
|
946
|
-
return createPlaceholderSchema();
|
|
947
|
-
}
|
|
948
|
-
const hasProperties = cleaned.properties &&
|
|
949
|
-
typeof cleaned.properties === "object" &&
|
|
950
|
-
Object.keys(cleaned.properties).length > 0;
|
|
951
|
-
cleaned.type = "object";
|
|
952
|
-
if (!hasProperties) {
|
|
953
|
-
cleaned.properties = {
|
|
954
|
-
[EMPTY_SCHEMA_PLACEHOLDER_NAME]: {
|
|
955
|
-
type: "boolean",
|
|
956
|
-
description: EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION,
|
|
957
|
-
},
|
|
958
|
-
};
|
|
959
|
-
cleaned.required = Array.isArray(cleaned.required)
|
|
960
|
-
? Array.from(new Set([...cleaned.required, EMPTY_SCHEMA_PLACEHOLDER_NAME]))
|
|
961
|
-
: [EMPTY_SCHEMA_PLACEHOLDER_NAME];
|
|
962
|
-
}
|
|
963
|
-
return cleaned;
|
|
964
|
-
};
|
|
965
|
-
requestPayload.tools.forEach((tool) => {
|
|
966
|
-
const pushDeclaration = (decl, source) => {
|
|
967
|
-
const schema = decl?.parameters ||
|
|
968
|
-
decl?.parametersJsonSchema ||
|
|
969
|
-
decl?.input_schema ||
|
|
970
|
-
decl?.inputSchema ||
|
|
971
|
-
tool.parameters ||
|
|
972
|
-
tool.parametersJsonSchema ||
|
|
973
|
-
tool.input_schema ||
|
|
974
|
-
tool.inputSchema ||
|
|
975
|
-
tool.function?.parameters ||
|
|
976
|
-
tool.function?.parametersJsonSchema ||
|
|
977
|
-
tool.function?.input_schema ||
|
|
978
|
-
tool.function?.inputSchema ||
|
|
979
|
-
tool.custom?.parameters ||
|
|
980
|
-
tool.custom?.parametersJsonSchema ||
|
|
981
|
-
tool.custom?.input_schema;
|
|
982
|
-
let name = decl?.name ||
|
|
983
|
-
tool.name ||
|
|
984
|
-
tool.function?.name ||
|
|
985
|
-
tool.custom?.name ||
|
|
986
|
-
`tool-${functionDeclarations.length}`;
|
|
987
|
-
name = String(name).replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64);
|
|
988
|
-
const description = decl?.description ||
|
|
989
|
-
tool.description ||
|
|
990
|
-
tool.function?.description ||
|
|
991
|
-
tool.custom?.description ||
|
|
992
|
-
"";
|
|
993
|
-
functionDeclarations.push({
|
|
994
|
-
name,
|
|
995
|
-
description: String(description || ""),
|
|
996
|
-
parameters: normalizeSchema(schema),
|
|
997
|
-
});
|
|
998
|
-
toolDebugSummaries.push(`decl=${name},src=${source},hasSchema=${schema ? "y" : "n"}`);
|
|
999
|
-
};
|
|
1000
|
-
if (Array.isArray(tool.functionDeclarations) && tool.functionDeclarations.length > 0) {
|
|
1001
|
-
tool.functionDeclarations.forEach((decl) => pushDeclaration(decl, "functionDeclarations"));
|
|
1002
|
-
return;
|
|
1003
|
-
}
|
|
1004
|
-
if (tool.function ||
|
|
1005
|
-
tool.custom ||
|
|
1006
|
-
tool.parameters ||
|
|
1007
|
-
tool.input_schema ||
|
|
1008
|
-
tool.inputSchema) {
|
|
1009
|
-
pushDeclaration(tool.function ?? tool.custom ?? tool, "function/custom");
|
|
1010
|
-
return;
|
|
1011
|
-
}
|
|
1012
|
-
passthroughTools.push(tool);
|
|
1013
|
-
});
|
|
1014
|
-
const finalTools = [];
|
|
1015
|
-
if (functionDeclarations.length > 0) {
|
|
1016
|
-
finalTools.push({ functionDeclarations });
|
|
1017
|
-
}
|
|
1018
|
-
requestPayload.tools = finalTools.concat(passthroughTools);
|
|
1019
|
-
}
|
|
1020
|
-
else {
|
|
1021
|
-
const geminiResult = applyGeminiTransforms(requestPayload, {
|
|
1022
|
-
model: effectiveModel,
|
|
1023
|
-
normalizedThinking: undefined, // Thinking config already applied above (lines 816-880)
|
|
1024
|
-
tierThinkingBudget,
|
|
1025
|
-
tierThinkingLevel: tierThinkingLevel,
|
|
1026
|
-
});
|
|
1027
|
-
toolDebugMissing = geminiResult.toolDebugMissing;
|
|
1028
|
-
toolDebugSummaries.push(...geminiResult.toolDebugSummaries);
|
|
1029
|
-
}
|
|
1030
|
-
try {
|
|
1031
|
-
toolDebugPayload = JSON.stringify(requestPayload.tools);
|
|
1032
|
-
}
|
|
1033
|
-
catch {
|
|
1034
|
-
toolDebugPayload = undefined;
|
|
1035
|
-
}
|
|
1036
|
-
// Can be disabled via config.claude_tool_hardening = false to reduce context size
|
|
1037
|
-
const enableToolHardening = options?.claudeToolHardening ?? true;
|
|
1038
|
-
if (enableToolHardening && isClaude && Array.isArray(requestPayload.tools) && requestPayload.tools.length > 0) {
|
|
1039
|
-
requestPayload.tools = injectParameterSignatures(requestPayload.tools, CLAUDE_DESCRIPTION_PROMPT);
|
|
1040
|
-
injectToolHardeningInstruction(requestPayload, CLAUDE_TOOL_SYSTEM_INSTRUCTION);
|
|
1041
|
-
}
|
|
1042
|
-
}
|
|
1043
|
-
const conversationKey = resolveConversationKey(requestPayload);
|
|
1044
|
-
signatureSessionKey = buildSignatureSessionKey(PLUGIN_SESSION_ID, effectiveModel, conversationKey, resolveProjectKey(projectId));
|
|
1045
|
-
if (isClaude) {
|
|
1046
|
-
sanitizeCrossModelPayloadInPlace(requestPayload, { targetModel: effectiveModel });
|
|
1047
|
-
deepFilterThinkingBlocks(requestPayload, signatureSessionKey, getCachedSignature, true);
|
|
1048
|
-
if (enableClaudePromptAutoCaching && requestPayload.cache_control === undefined) {
|
|
1049
|
-
requestPayload.cache_control = { type: "ephemeral" };
|
|
1050
|
-
}
|
|
1051
|
-
if (isClaudeThinking && keepThinkingEnabled && Array.isArray(requestPayload.contents)) {
|
|
1052
|
-
requestPayload.contents = ensureThinkingBeforeToolUseInContents(requestPayload.contents, signatureSessionKey);
|
|
1053
|
-
}
|
|
1054
|
-
if (isClaudeThinking && keepThinkingEnabled && Array.isArray(requestPayload.messages)) {
|
|
1055
|
-
requestPayload.messages = ensureThinkingBeforeToolUseInMessages(requestPayload.messages, signatureSessionKey);
|
|
1056
|
-
}
|
|
1057
|
-
if (isClaudeThinking && keepThinkingEnabled) {
|
|
1058
|
-
const hasToolUse = (Array.isArray(requestPayload.contents) && hasToolUseInContents(requestPayload.contents)) ||
|
|
1059
|
-
(Array.isArray(requestPayload.messages) && hasToolUseInMessages(requestPayload.messages));
|
|
1060
|
-
const hasSignedThinking = (Array.isArray(requestPayload.contents) && hasSignedThinkingInContents(requestPayload.contents, signatureSessionKey)) ||
|
|
1061
|
-
(Array.isArray(requestPayload.messages) && hasSignedThinkingInMessages(requestPayload.messages, signatureSessionKey));
|
|
1062
|
-
const hasCachedThinking = defaultSignatureStore.has(signatureSessionKey);
|
|
1063
|
-
needsSignedThinkingWarmup = hasToolUse && !hasSignedThinking && !hasCachedThinking;
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
if (isClaude && Array.isArray(requestPayload.contents)) {
|
|
1067
|
-
let toolCallCounter = 0;
|
|
1068
|
-
const pendingCallIdsByName = new Map();
|
|
1069
|
-
requestPayload.contents = requestPayload.contents.map((content) => {
|
|
1070
|
-
if (!content || !Array.isArray(content.parts)) {
|
|
1071
|
-
return content;
|
|
1072
|
-
}
|
|
1073
|
-
const newParts = content.parts.map((part) => {
|
|
1074
|
-
if (part && typeof part === "object" && part.functionCall) {
|
|
1075
|
-
const call = { ...part.functionCall };
|
|
1076
|
-
if (!call.id) {
|
|
1077
|
-
call.id = `tool-call-${++toolCallCounter}`;
|
|
1078
|
-
}
|
|
1079
|
-
const nameKey = typeof call.name === "string" ? call.name : `tool-${toolCallCounter}`;
|
|
1080
|
-
const queue = pendingCallIdsByName.get(nameKey) || [];
|
|
1081
|
-
queue.push(call.id);
|
|
1082
|
-
pendingCallIdsByName.set(nameKey, queue);
|
|
1083
|
-
return { ...part, functionCall: call };
|
|
1084
|
-
}
|
|
1085
|
-
return part;
|
|
1086
|
-
});
|
|
1087
|
-
return { ...content, parts: newParts };
|
|
1088
|
-
});
|
|
1089
|
-
requestPayload.contents = requestPayload.contents.map((content) => {
|
|
1090
|
-
if (!content || !Array.isArray(content.parts)) {
|
|
1091
|
-
return content;
|
|
1092
|
-
}
|
|
1093
|
-
const newParts = content.parts.map((part) => {
|
|
1094
|
-
if (part && typeof part === "object" && part.functionResponse) {
|
|
1095
|
-
const resp = { ...part.functionResponse };
|
|
1096
|
-
if (!resp.id && typeof resp.name === "string") {
|
|
1097
|
-
const queue = pendingCallIdsByName.get(resp.name);
|
|
1098
|
-
if (queue && queue.length > 0) {
|
|
1099
|
-
resp.id = queue.shift();
|
|
1100
|
-
pendingCallIdsByName.set(resp.name, queue);
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
return { ...part, functionResponse: resp };
|
|
1104
|
-
}
|
|
1105
|
-
return part;
|
|
1106
|
-
});
|
|
1107
|
-
return { ...content, parts: newParts };
|
|
1108
|
-
});
|
|
1109
|
-
// Ported from LLM-API-Key-Proxy's _fix_tool_response_grouping()
|
|
1110
|
-
requestPayload.contents = fixToolResponseGrouping(requestPayload.contents);
|
|
1111
|
-
}
|
|
1112
|
-
// Handles orphaned tool_use blocks in Claude's messages[] format
|
|
1113
|
-
if (Array.isArray(requestPayload.messages)) {
|
|
1114
|
-
requestPayload.messages = validateAndFixClaudeToolPairing(requestPayload.messages);
|
|
1115
|
-
}
|
|
1116
|
-
// =====================================================================
|
|
1117
|
-
// =====================================================================
|
|
1118
|
-
//
|
|
1119
|
-
// - Context compaction stripped thinking blocks
|
|
1120
|
-
// - Signature cache miss
|
|
1121
|
-
// - Any other corruption we couldn't repair
|
|
1122
|
-
// - API error indicated thinking_block_order issue (forceThinkingRecovery=true)
|
|
1123
|
-
//
|
|
1124
|
-
if (isClaudeThinking && Array.isArray(requestPayload.contents)) {
|
|
1125
|
-
const conversationState = analyzeConversationState(requestPayload.contents);
|
|
1126
|
-
// Force recovery if API returned thinking_block_order error (retry case)
|
|
1127
|
-
if (forceThinkingRecovery || needsThinkingRecovery(conversationState)) {
|
|
1128
|
-
thinkingRecoveryMessage = forceThinkingRecovery
|
|
1129
|
-
? "Thinking recovery: retrying with fresh turn (API error)"
|
|
1130
|
-
: "Thinking recovery: restarting turn (corrupted context)";
|
|
1131
|
-
requestPayload.contents = closeToolLoopForThinking(requestPayload.contents);
|
|
1132
|
-
defaultSignatureStore.delete(signatureSessionKey);
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
if ("model" in requestPayload) {
|
|
1136
|
-
delete requestPayload.model;
|
|
1137
|
-
}
|
|
1138
|
-
stripInjectedDebugFromRequestPayload(requestPayload);
|
|
1139
|
-
sanitizeRequestPayloadForAntigravity(requestPayload);
|
|
1140
|
-
try {
|
|
1141
|
-
if (!isClaude && Array.isArray(requestPayload.contents) && options?.debugGeminiPayloads) {
|
|
1142
|
-
const fs = require('fs');
|
|
1143
|
-
fs.appendFileSync(require('path').join(require('os').homedir(), '.config', 'opencode', 'gemini-payload-debug.log'), "\n\n=== PAYLOAD BEFORE ===\n" + JSON.stringify(requestPayload.contents, null, 2));
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
catch (e) { }
|
|
1147
|
-
if (!isClaude && Array.isArray(requestPayload.contents)) {
|
|
1148
|
-
requestPayload.contents = sanitizeGeminiContents(requestPayload.contents);
|
|
1149
|
-
requestPayload.contents = fixGeminiToolPairing(requestPayload.contents);
|
|
1150
|
-
requestPayload.contents = sanitizeGeminiContents(requestPayload.contents);
|
|
1151
|
-
}
|
|
1152
|
-
const effectiveProjectId = projectId?.trim() || (headerStyle === "antigravity" ? generateSyntheticProjectId() : "");
|
|
1153
|
-
resolvedProjectId = effectiveProjectId;
|
|
1154
|
-
try {
|
|
1155
|
-
if (!isClaude && Array.isArray(requestPayload.contents) && options?.debugGeminiPayloads) {
|
|
1156
|
-
const fs = require('fs');
|
|
1157
|
-
fs.appendFileSync(require('path').join(require('os').homedir(), '.config', 'opencode', 'gemini-payload-debug.log'), "\n\n=== PAYLOAD AFTER ===\n" + JSON.stringify(requestPayload.contents, null, 2));
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
catch (e) { }
|
|
1161
|
-
if (headerStyle === "antigravity") {
|
|
1162
|
-
const existingSystemInstruction = requestPayload.systemInstruction;
|
|
1163
|
-
if (existingSystemInstruction && typeof existingSystemInstruction === "object") {
|
|
1164
|
-
const sys = existingSystemInstruction;
|
|
1165
|
-
sys.role = "user";
|
|
1166
|
-
if (Array.isArray(sys.parts) && sys.parts.length > 0) {
|
|
1167
|
-
const firstPart = sys.parts[0];
|
|
1168
|
-
if (firstPart && typeof firstPart.text === "string") {
|
|
1169
|
-
firstPart.text = ANTIGRAVITY_SYSTEM_INSTRUCTION + "\n\n" + firstPart.text;
|
|
1170
|
-
}
|
|
1171
|
-
else {
|
|
1172
|
-
sys.parts = [{ text: ANTIGRAVITY_SYSTEM_INSTRUCTION }, ...sys.parts];
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
else {
|
|
1176
|
-
sys.parts = [{ text: ANTIGRAVITY_SYSTEM_INSTRUCTION }];
|
|
1177
|
-
}
|
|
1178
|
-
}
|
|
1179
|
-
else if (typeof existingSystemInstruction === "string") {
|
|
1180
|
-
requestPayload.systemInstruction = {
|
|
1181
|
-
role: "user",
|
|
1182
|
-
parts: [{ text: ANTIGRAVITY_SYSTEM_INSTRUCTION + "\n\n" + existingSystemInstruction }],
|
|
1183
|
-
};
|
|
1184
|
-
}
|
|
1185
|
-
else {
|
|
1186
|
-
requestPayload.systemInstruction = {
|
|
1187
|
-
role: "user",
|
|
1188
|
-
parts: [{ text: ANTIGRAVITY_SYSTEM_INSTRUCTION }],
|
|
1189
|
-
};
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
const wrappedBody = {
|
|
1193
|
-
project: effectiveProjectId,
|
|
1194
|
-
model: effectiveModel,
|
|
1195
|
-
request: requestPayload,
|
|
1196
|
-
};
|
|
1197
|
-
if (headerStyle === "antigravity") {
|
|
1198
|
-
wrappedBody.requestType = "agent";
|
|
1199
|
-
wrappedBody.userAgent = "antigravity";
|
|
1200
|
-
wrappedBody.requestId = "agent-" + crypto.randomUUID();
|
|
1201
|
-
}
|
|
1202
|
-
if (wrappedBody.request && typeof wrappedBody.request === 'object') {
|
|
1203
|
-
sessionId = signatureSessionKey;
|
|
1204
|
-
wrappedBody.request.sessionId = signatureSessionKey;
|
|
1205
|
-
}
|
|
1206
|
-
body = JSON.stringify(wrappedBody);
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
catch (error) {
|
|
1210
|
-
throw error;
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
if (streaming) {
|
|
1214
|
-
headers.set("Accept", "text/event-stream");
|
|
1215
|
-
}
|
|
1216
|
-
if (isClaudeThinking) {
|
|
1217
|
-
const existing = headers.get("anthropic-beta");
|
|
1218
|
-
const interleavedHeader = "interleaved-thinking-2025-05-14";
|
|
1219
|
-
if (existing) {
|
|
1220
|
-
if (!existing.includes(interleavedHeader)) {
|
|
1221
|
-
headers.set("anthropic-beta", `${existing},${interleavedHeader}`);
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
else {
|
|
1225
|
-
headers.set("anthropic-beta", interleavedHeader);
|
|
1226
|
-
}
|
|
1227
|
-
}
|
|
1228
|
-
if (headerStyle === "antigravity") {
|
|
1229
|
-
const selectedHeaders = getRandomizedHeaders("antigravity", requestedModel);
|
|
1230
|
-
// (ideType=ANTIGRAVITY goes in request body metadata via project.ts, not as a header)
|
|
1231
|
-
const fingerprint = options?.fingerprint ?? getSessionFingerprint();
|
|
1232
|
-
const fingerprintHeaders = buildFingerprintHeaders(fingerprint);
|
|
1233
|
-
headers.set("User-Agent", fingerprintHeaders["User-Agent"] || selectedHeaders["User-Agent"]);
|
|
1234
|
-
}
|
|
1235
|
-
else {
|
|
1236
|
-
headers.set("User-Agent", GEMINI_CLI_HEADERS["User-Agent"]);
|
|
1237
|
-
headers.set("X-Goog-Api-Client", GEMINI_CLI_HEADERS["X-Goog-Api-Client"]);
|
|
1238
|
-
headers.set("Client-Metadata", GEMINI_CLI_HEADERS["Client-Metadata"]);
|
|
1239
|
-
}
|
|
1240
|
-
return {
|
|
1241
|
-
request: transformedUrl,
|
|
1242
|
-
init: {
|
|
1243
|
-
...baseInit,
|
|
1244
|
-
headers,
|
|
1245
|
-
body,
|
|
1246
|
-
},
|
|
1247
|
-
streaming,
|
|
1248
|
-
requestedModel,
|
|
1249
|
-
effectiveModel: effectiveModel,
|
|
1250
|
-
projectId: resolvedProjectId,
|
|
1251
|
-
endpoint: transformedUrl,
|
|
1252
|
-
sessionId,
|
|
1253
|
-
toolDebugMissing,
|
|
1254
|
-
toolDebugSummary: toolDebugSummaries.slice(0, 20).join(" | "),
|
|
1255
|
-
toolDebugPayload,
|
|
1256
|
-
needsSignedThinkingWarmup,
|
|
1257
|
-
headerStyle,
|
|
1258
|
-
thinkingRecoveryMessage,
|
|
1259
|
-
};
|
|
1260
|
-
}
|
|
1261
|
-
export function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
|
|
1262
|
-
if (!bodyText || !isClaudeThinking) {
|
|
1263
|
-
return null;
|
|
1264
|
-
}
|
|
1265
|
-
let parsed;
|
|
1266
|
-
try {
|
|
1267
|
-
parsed = JSON.parse(bodyText);
|
|
1268
|
-
}
|
|
1269
|
-
catch {
|
|
1270
|
-
return null;
|
|
1271
|
-
}
|
|
1272
|
-
const warmupPrompt = "Warmup request for thinking signature.";
|
|
1273
|
-
const updateRequest = (req) => {
|
|
1274
|
-
req.contents = [{ role: "user", parts: [{ text: warmupPrompt }] }];
|
|
1275
|
-
delete req.tools;
|
|
1276
|
-
delete req.toolConfig;
|
|
1277
|
-
const generationConfig = (req.generationConfig ?? {});
|
|
1278
|
-
generationConfig.thinkingConfig = {
|
|
1279
|
-
include_thoughts: true,
|
|
1280
|
-
thinking_budget: DEFAULT_THINKING_BUDGET,
|
|
1281
|
-
};
|
|
1282
|
-
generationConfig.maxOutputTokens = CLAUDE_THINKING_MAX_OUTPUT_TOKENS;
|
|
1283
|
-
req.generationConfig = generationConfig;
|
|
1284
|
-
};
|
|
1285
|
-
if (parsed.request && typeof parsed.request === "object") {
|
|
1286
|
-
updateRequest(parsed.request);
|
|
1287
|
-
const nested = parsed.request.request;
|
|
1288
|
-
if (nested && typeof nested === "object") {
|
|
1289
|
-
updateRequest(nested);
|
|
1290
|
-
}
|
|
1291
|
-
}
|
|
1292
|
-
else {
|
|
1293
|
-
updateRequest(parsed);
|
|
1294
|
-
}
|
|
1295
|
-
return JSON.stringify(parsed);
|
|
1296
|
-
}
|
|
1297
|
-
/**
|
|
1298
|
-
* Normalizes Antigravity responses: applies retry headers, extracts cache usage into headers,
|
|
1299
|
-
* rewrites preview errors, flattens streaming payloads, and logs debug metadata.
|
|
1300
|
-
*
|
|
1301
|
-
* For streaming SSE responses, uses TransformStream for true real-time incremental streaming.
|
|
1302
|
-
* Thinking/reasoning tokens are transformed and forwarded immediately as they arrive.
|
|
1303
|
-
*/
|
|
1304
|
-
export async function transformAntigravityResponse(response, streaming, debugContext, requestedModel, projectId, endpoint, effectiveModel, sessionId, toolDebugMissing, toolDebugSummary, toolDebugPayload, debugLines, onComplete, onWatchdogTimeout) {
|
|
1305
|
-
const contentType = response.headers.get("content-type") ?? "";
|
|
1306
|
-
const isJsonResponse = contentType.includes("application/json");
|
|
1307
|
-
const isEventStreamResponse = contentType.includes("text/event-stream");
|
|
1308
|
-
// - If debug=true: inject full debug logs
|
|
1309
|
-
// - If keep_thinking=true (but no debug): inject placeholder to trigger signature caching
|
|
1310
|
-
const debugText = isDebugTuiEnabled() && Array.isArray(debugLines) && debugLines.length > 0
|
|
1311
|
-
? formatDebugLinesForThinking(debugLines)
|
|
1312
|
-
: getKeepThinking()
|
|
1313
|
-
? SYNTHETIC_THINKING_PLACEHOLDER
|
|
1314
|
-
: undefined;
|
|
1315
|
-
const cacheSignatures = shouldCacheThinkingSignatures(effectiveModel);
|
|
1316
|
-
if (!isJsonResponse && !isEventStreamResponse) {
|
|
1317
|
-
logAntigravityDebugResponse(debugContext, response, {
|
|
1318
|
-
note: "Non-JSON response (body omitted)",
|
|
1319
|
-
});
|
|
1320
|
-
return response;
|
|
1321
|
-
}
|
|
1322
|
-
if (streaming && response.ok && isEventStreamResponse && response.body) {
|
|
1323
|
-
const headers = new Headers(response.headers);
|
|
1324
|
-
logAntigravityDebugResponse(debugContext, response, {
|
|
1325
|
-
note: "Streaming SSE response (real-time transform)",
|
|
1326
|
-
});
|
|
1327
|
-
const streamingTransformer = createStreamingTransformer(defaultSignatureStore, {
|
|
1328
|
-
onCacheSignature: cacheSignature,
|
|
1329
|
-
onInjectDebug: injectDebugThinking,
|
|
1330
|
-
// onInjectSyntheticThinking removed - keep_thinking now uses debugText path
|
|
1331
|
-
transformThinkingParts,
|
|
1332
|
-
}, {
|
|
1333
|
-
signatureSessionKey: sessionId,
|
|
1334
|
-
debugText,
|
|
1335
|
-
cacheSignatures,
|
|
1336
|
-
displayedThinkingHashes: effectiveModel && isGemini3Model(effectiveModel) ? sessionDisplayedThinkingHashes : undefined,
|
|
1337
|
-
onComplete,
|
|
1338
|
-
onWatchdogTimeout,
|
|
1339
|
-
});
|
|
1340
|
-
return new Response(response.body.pipeThrough(streamingTransformer), {
|
|
1341
|
-
status: response.status,
|
|
1342
|
-
statusText: response.statusText,
|
|
1343
|
-
headers,
|
|
1344
|
-
});
|
|
1345
|
-
}
|
|
1346
|
-
const responseFallback = response.clone();
|
|
1347
|
-
try {
|
|
1348
|
-
const headers = new Headers(response.headers);
|
|
1349
|
-
const text = await response.text();
|
|
1350
|
-
if (!response.ok) {
|
|
1351
|
-
let errorBody;
|
|
1352
|
-
try {
|
|
1353
|
-
errorBody = JSON.parse(text);
|
|
1354
|
-
}
|
|
1355
|
-
catch {
|
|
1356
|
-
errorBody = { error: { message: text } };
|
|
1357
|
-
}
|
|
1358
|
-
if (errorBody?.error) {
|
|
1359
|
-
const rawErrorMessage = typeof errorBody.error.message === "string" && errorBody.error.message.length > 0
|
|
1360
|
-
? errorBody.error.message
|
|
1361
|
-
: "Unknown error";
|
|
1362
|
-
const errorType = detectErrorType(rawErrorMessage);
|
|
1363
|
-
const debugInfo = `\n\n[Debug Info]\nRequested Model: ${requestedModel || "Unknown"}\nEffective Model: ${effectiveModel || "Unknown"}\nProject: ${projectId || "Unknown"}\nEndpoint: ${endpoint || "Unknown"}\nStatus: ${response.status}\nRequest ID: ${headers.get("x-request-id") || "N/A"}${toolDebugMissing !== undefined ? `\nTool Debug Missing: ${toolDebugMissing}` : ""}${toolDebugSummary ? `\nTool Debug Summary: ${toolDebugSummary}` : ""}${toolDebugPayload ? `\nTool Debug Payload: ${toolDebugPayload}` : ""}`;
|
|
1364
|
-
const injectedDebug = debugText ? `\n\n${debugText}` : "";
|
|
1365
|
-
errorBody.error.message = rawErrorMessage + debugInfo + injectedDebug;
|
|
1366
|
-
if (errorType === "thinking_block_order") {
|
|
1367
|
-
const recoveryError = new Error("THINKING_RECOVERY_NEEDED");
|
|
1368
|
-
recoveryError.recoveryType = errorType;
|
|
1369
|
-
recoveryError.originalError = errorBody;
|
|
1370
|
-
recoveryError.debugInfo = debugInfo;
|
|
1371
|
-
throw recoveryError;
|
|
1372
|
-
}
|
|
1373
|
-
const errorMessage = errorBody.error.message?.toLowerCase() || "";
|
|
1374
|
-
if (errorMessage.includes("prompt is too long") ||
|
|
1375
|
-
errorMessage.includes("context length exceeded") ||
|
|
1376
|
-
errorMessage.includes("context_length_exceeded") ||
|
|
1377
|
-
errorMessage.includes("maximum context length")) {
|
|
1378
|
-
headers.set("x-antigravity-context-error", "prompt_too_long");
|
|
1379
|
-
}
|
|
1380
|
-
if (errorMessage.includes("tool_use") &&
|
|
1381
|
-
errorMessage.includes("tool_result") &&
|
|
1382
|
-
(errorMessage.includes("without") || errorMessage.includes("immediately after"))) {
|
|
1383
|
-
headers.set("x-antigravity-context-error", "tool_pairing");
|
|
1384
|
-
}
|
|
1385
|
-
return new Response(JSON.stringify(errorBody), {
|
|
1386
|
-
status: response.status,
|
|
1387
|
-
statusText: response.statusText,
|
|
1388
|
-
headers
|
|
1389
|
-
});
|
|
1390
|
-
}
|
|
1391
|
-
if (errorBody?.error?.details && Array.isArray(errorBody.error.details)) {
|
|
1392
|
-
const retryInfo = errorBody.error.details.find((detail) => detail['@type'] === 'type.googleapis.com/google.rpc.RetryInfo');
|
|
1393
|
-
if (retryInfo?.retryDelay) {
|
|
1394
|
-
const match = retryInfo.retryDelay.match(/^([\d.]+)s$/);
|
|
1395
|
-
if (match && match[1]) {
|
|
1396
|
-
const retrySeconds = parseFloat(match[1]);
|
|
1397
|
-
if (!isNaN(retrySeconds) && retrySeconds > 0) {
|
|
1398
|
-
const retryAfterSec = Math.ceil(retrySeconds).toString();
|
|
1399
|
-
const retryAfterMs = Math.ceil(retrySeconds * 1000).toString();
|
|
1400
|
-
headers.set('Retry-After', retryAfterSec);
|
|
1401
|
-
headers.set('retry-after-ms', retryAfterMs);
|
|
1402
|
-
}
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
}
|
|
1407
|
-
const init = {
|
|
1408
|
-
status: response.status,
|
|
1409
|
-
statusText: response.statusText,
|
|
1410
|
-
headers,
|
|
1411
|
-
};
|
|
1412
|
-
const usageFromSse = streaming && isEventStreamResponse ? extractUsageFromSsePayload(text) : null;
|
|
1413
|
-
const parsed = !streaming || !isEventStreamResponse ? parseAntigravityApiBody(text) : null;
|
|
1414
|
-
const patched = parsed ? rewriteAntigravityPreviewAccessError(parsed, response.status, requestedModel) : null;
|
|
1415
|
-
const effectiveBody = patched ?? parsed ?? undefined;
|
|
1416
|
-
const usage = usageFromSse ?? (effectiveBody ? extractUsageMetadata(effectiveBody) : null);
|
|
1417
|
-
if (usage && effectiveModel) {
|
|
1418
|
-
logCacheStats(effectiveModel, usage.cachedContentTokenCount ?? 0, 0, // API doesn't provide cache write tokens separately
|
|
1419
|
-
usage.promptTokenCount ?? usage.totalTokenCount ?? 0);
|
|
1420
|
-
}
|
|
1421
|
-
if (usage?.cachedContentTokenCount !== undefined) {
|
|
1422
|
-
headers.set("x-antigravity-cached-content-token-count", String(usage.cachedContentTokenCount));
|
|
1423
|
-
if (usage.totalTokenCount !== undefined) {
|
|
1424
|
-
headers.set("x-antigravity-total-token-count", String(usage.totalTokenCount));
|
|
1425
|
-
}
|
|
1426
|
-
if (usage.promptTokenCount !== undefined) {
|
|
1427
|
-
headers.set("x-antigravity-prompt-token-count", String(usage.promptTokenCount));
|
|
1428
|
-
}
|
|
1429
|
-
if (usage.candidatesTokenCount !== undefined) {
|
|
1430
|
-
headers.set("x-antigravity-candidates-token-count", String(usage.candidatesTokenCount));
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
logAntigravityDebugResponse(debugContext, response, {
|
|
1434
|
-
body: text,
|
|
1435
|
-
note: streaming ? "Streaming SSE payload (buffered fallback)" : undefined,
|
|
1436
|
-
headersOverride: headers,
|
|
1437
|
-
});
|
|
1438
|
-
if (!parsed) {
|
|
1439
|
-
return new Response(text, init);
|
|
1440
|
-
}
|
|
1441
|
-
if (effectiveBody?.response !== undefined) {
|
|
1442
|
-
let responseBody = effectiveBody.response;
|
|
1443
|
-
// Both debug=true and keep_thinking=true use the same path now
|
|
1444
|
-
if (debugText) {
|
|
1445
|
-
responseBody = injectDebugThinking(responseBody, debugText);
|
|
1446
|
-
}
|
|
1447
|
-
const transformed = transformThinkingParts(responseBody);
|
|
1448
|
-
return new Response(JSON.stringify(transformed), init);
|
|
1449
|
-
}
|
|
1450
|
-
if (patched) {
|
|
1451
|
-
return new Response(JSON.stringify(patched), init);
|
|
1452
|
-
}
|
|
1453
|
-
return new Response(text, init);
|
|
1454
|
-
}
|
|
1455
|
-
catch (error) {
|
|
1456
|
-
if (error instanceof Error && error.message === "THINKING_RECOVERY_NEEDED") {
|
|
1457
|
-
throw error;
|
|
1458
|
-
}
|
|
1459
|
-
logAntigravityDebugResponse(debugContext, response, {
|
|
1460
|
-
error,
|
|
1461
|
-
note: "Failed to transform Antigravity response",
|
|
1462
|
-
});
|
|
1463
|
-
return responseFallback;
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
export const __testExports = {
|
|
1467
|
-
buildSignatureSessionKey,
|
|
1468
|
-
hashConversationSeed,
|
|
1469
|
-
extractTextFromContent,
|
|
1470
|
-
extractConversationSeedFromMessages,
|
|
1471
|
-
extractConversationSeedFromContents,
|
|
1472
|
-
resolveConversationKey,
|
|
1473
|
-
resolveProjectKey,
|
|
1474
|
-
isGeminiToolUsePart,
|
|
1475
|
-
isGeminiThinkingPart,
|
|
1476
|
-
ensureThoughtSignature,
|
|
1477
|
-
hasSignedThinkingPart,
|
|
1478
|
-
hasSignedThinkingInContents,
|
|
1479
|
-
hasSignedThinkingInMessages,
|
|
1480
|
-
hasToolUseInContents,
|
|
1481
|
-
hasToolUseInMessages,
|
|
1482
|
-
ensureThinkingBeforeToolUseInContents,
|
|
1483
|
-
ensureThinkingBeforeToolUseInMessages,
|
|
1484
|
-
generateSyntheticProjectId,
|
|
1485
|
-
MIN_SIGNATURE_LENGTH,
|
|
1486
|
-
transformSseLine,
|
|
1487
|
-
transformStreamingPayload,
|
|
1488
|
-
createStreamingTransformer,
|
|
1489
|
-
};
|