@cortexkit/opencode-antigravity-auth 1.0.0 → 1.1.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 +24 -8
- package/dist/index.js +1450 -467
- package/dist/index.js.map +4 -4
- package/dist/src/plugin/accounts.d.ts +36 -9
- package/dist/src/plugin/accounts.d.ts.map +1 -1
- package/dist/src/plugin/accounts.js +269 -57
- package/dist/src/plugin/accounts.js.map +1 -1
- package/dist/src/plugin/agy-request-metadata.d.ts +2 -0
- package/dist/src/plugin/agy-request-metadata.d.ts.map +1 -0
- package/dist/src/plugin/agy-request-metadata.js +2 -0
- package/dist/src/plugin/agy-request-metadata.js.map +1 -0
- package/dist/src/plugin/auth-doctor.d.ts +1 -1
- package/dist/src/plugin/auth-doctor.d.ts.map +1 -1
- package/dist/src/plugin/auth-doctor.js +9 -0
- package/dist/src/plugin/auth-doctor.js.map +1 -1
- package/dist/src/plugin/debug.d.ts.map +1 -1
- package/dist/src/plugin/debug.js +3 -2
- package/dist/src/plugin/debug.js.map +1 -1
- package/dist/src/plugin/gemini-dump.d.ts.map +1 -1
- package/dist/src/plugin/gemini-dump.js +8 -4
- package/dist/src/plugin/gemini-dump.js.map +1 -1
- package/dist/src/plugin/image-saver.d.ts +2 -21
- package/dist/src/plugin/image-saver.d.ts.map +1 -1
- package/dist/src/plugin/image-saver.js +29 -63
- package/dist/src/plugin/image-saver.js.map +1 -1
- package/dist/src/plugin/request-helpers.d.ts +1 -0
- package/dist/src/plugin/request-helpers.d.ts.map +1 -1
- package/dist/src/plugin/request-helpers.js +9 -4
- package/dist/src/plugin/request-helpers.js.map +1 -1
- package/dist/src/plugin/request.d.ts +15 -4
- package/dist/src/plugin/request.d.ts.map +1 -1
- package/dist/src/plugin/request.js +255 -71
- package/dist/src/plugin/request.js.map +1 -1
- package/dist/src/plugin/session-context.d.ts +21 -0
- package/dist/src/plugin/session-context.d.ts.map +1 -0
- package/dist/src/plugin/session-context.js +63 -0
- package/dist/src/plugin/session-context.js.map +1 -0
- package/dist/src/plugin/storage.d.ts +6 -0
- package/dist/src/plugin/storage.d.ts.map +1 -1
- package/dist/src/plugin/storage.js +27 -6
- package/dist/src/plugin/storage.js.map +1 -1
- package/dist/src/plugin/ui/auth-menu.d.ts +1 -1
- package/dist/src/plugin/ui/auth-menu.d.ts.map +1 -1
- package/dist/src/plugin/ui/auth-menu.js +3 -1
- package/dist/src/plugin/ui/auth-menu.js.map +1 -1
- package/dist/src/plugin/ui/quota-status.d.ts.map +1 -1
- package/dist/src/plugin/ui/quota-status.js +2 -1
- package/dist/src/plugin/ui/quota-status.js.map +1 -1
- package/dist/src/plugin.d.ts +16 -0
- package/dist/src/plugin.d.ts.map +1 -1
- package/dist/src/plugin.js +288 -102
- package/dist/src/plugin.js.map +1 -1
- package/package.json +2 -2
- package/dist/src/plugin/transform/claude.d.ts +0 -92
- package/dist/src/plugin/transform/claude.d.ts.map +0 -1
- package/dist/src/plugin/transform/claude.js +0 -280
- package/dist/src/plugin/transform/claude.js.map +0 -1
- package/dist/src/plugin/transform/gemini.d.ts +0 -100
- package/dist/src/plugin/transform/gemini.d.ts.map +0 -1
- package/dist/src/plugin/transform/gemini.js +0 -446
- package/dist/src/plugin/transform/gemini.js.map +0 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import crypto from "node:crypto";
|
|
2
|
-
import { ANTIGRAVITY_ENDPOINT, GEMINI_CLI_ENDPOINT, EMPTY_SCHEMA_PLACEHOLDER_NAME, EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION, SKIP_THOUGHT_SIGNATURE, getRandomizedHeaders, } from "../constants";
|
|
2
|
+
import { ANTIGRAVITY_ENDPOINT, ANTIGRAVITY_DEFAULT_PROJECT_ID, GEMINI_CLI_ENDPOINT, EMPTY_SCHEMA_PLACEHOLDER_NAME, EMPTY_SCHEMA_PLACEHOLDER_DESCRIPTION, SKIP_THOUGHT_SIGNATURE, getRandomizedHeaders, } from "../constants";
|
|
3
3
|
import { cacheSignature, getCachedSignature } from "./cache";
|
|
4
4
|
import { getKeepThinking } from "./config";
|
|
5
5
|
import { createStreamingTransformer, transformSseLine, transformStreamingPayload, } from "./core/streaming";
|
|
6
6
|
import { defaultSignatureStore } from "./stores/signature-store";
|
|
7
7
|
import { DEBUG_MESSAGE_PREFIX, isDebugEnabled, isDebugTuiEnabled, logAntigravityDebugResponse, logCacheStats, } from "./debug";
|
|
8
8
|
import { createLogger } from "./logger";
|
|
9
|
-
import { cleanJSONSchemaForAntigravity,
|
|
9
|
+
import { cleanJSONSchemaForAntigravity, deepFilterThinkingBlocks, extractThinkingConfig, extractVariantThinkingConfig, extractUsageFromSsePayload, extractUsageMetadata, fixToolResponseGrouping, validateAndFixClaudeToolPairing, applyToolPairingFixes, injectParameterSignatures, injectToolHardeningInstruction, isThinkingCapableModel, normalizeThinkingConfig, parseAntigravityApiBody, resolveThinkingConfig, rewriteAntigravityPreviewAccessError, transformThinkingParts, } from "./request-helpers";
|
|
10
10
|
import { CLAUDE_TOOL_SYSTEM_INSTRUCTION, CLAUDE_DESCRIPTION_PROMPT, } from "../constants";
|
|
11
11
|
import { analyzeConversationState, closeToolLoopForThinking, needsThinkingRecovery, } from "./thinking-recovery";
|
|
12
12
|
import { sanitizeCrossModelPayloadInPlace } from "./transform/cross-model-sanitizer";
|
|
@@ -14,11 +14,14 @@ import { isGemini3Model, isImageGenerationModel, buildImageGenerationConfig, app
|
|
|
14
14
|
import { resolveModelWithTier, resolveModelWithVariant, resolveModelForHeaderStyle, isClaudeModel, isClaudeThinkingModel, CLAUDE_THINKING_MAX_OUTPUT_TOKENS, computeClaudeMaxOutputTokens, appendClaudeThinkingHint, } from "./transform";
|
|
15
15
|
import { detectErrorType } from "./recovery";
|
|
16
16
|
import { getSessionFingerprint, buildFingerprintHeaders } from "./fingerprint";
|
|
17
|
+
import { buildAgyAgentRequestMetadata, createAgyRequestSessionContext, orderAgyRequestPayloadInPlace, } from "./agy-request-metadata";
|
|
17
18
|
import { appendGeminiDumpResponseText, createGeminiDumpResponseTransform, noteGeminiDumpResponse, } from "./gemini-dump";
|
|
18
19
|
const log = createLogger("request");
|
|
19
20
|
const PLUGIN_SESSION_ID = `-${crypto.randomUUID()}`;
|
|
21
|
+
const DEFAULT_AGY_REQUEST_SESSION = createAgyRequestSessionContext("");
|
|
20
22
|
const sessionDisplayedThinkingHashes = new Set();
|
|
21
23
|
const MIN_SIGNATURE_LENGTH = 50;
|
|
24
|
+
const AGY_CLAUDE_THINKING_BUDGET = 1024;
|
|
22
25
|
const ANTIGRAVITY_ENVELOPE_FIELD_ORDER = [
|
|
23
26
|
"project",
|
|
24
27
|
"requestId",
|
|
@@ -26,17 +29,71 @@ const ANTIGRAVITY_ENVELOPE_FIELD_ORDER = [
|
|
|
26
29
|
"model",
|
|
27
30
|
"userAgent",
|
|
28
31
|
"requestType",
|
|
29
|
-
"enabledCreditTypes",
|
|
30
32
|
];
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
const OPENCODE_TITLE_PROMPT_PREFIX = "Generate a title for this conversation:";
|
|
34
|
+
function getOpenCodeTitleSourceText(payload) {
|
|
35
|
+
if (!Array.isArray(payload.contents)) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const texts = payload.contents.flatMap((content) => {
|
|
39
|
+
if (!content || typeof content !== "object") {
|
|
40
|
+
return [];
|
|
41
|
+
}
|
|
42
|
+
const parts = content.parts;
|
|
43
|
+
if (!Array.isArray(parts)) {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
return parts.flatMap((part) => !!part && typeof part === "object" && typeof part.text === "string"
|
|
47
|
+
? [part.text]
|
|
48
|
+
: []);
|
|
49
|
+
});
|
|
50
|
+
const promptIndex = texts.findIndex((text) => text.startsWith(OPENCODE_TITLE_PROMPT_PREFIX));
|
|
51
|
+
return promptIndex >= 0 ? texts.slice(promptIndex + 1).find((text) => text.trim().length > 0) : undefined;
|
|
52
|
+
}
|
|
53
|
+
function isOpenCodeTitleGenerationRequest(payload) {
|
|
54
|
+
return getOpenCodeTitleSourceText(payload) !== undefined;
|
|
55
|
+
}
|
|
56
|
+
function formatLocalImageTitle(sourceText) {
|
|
57
|
+
const normalized = sourceText
|
|
58
|
+
.trim()
|
|
59
|
+
.replace(/^(["“])(.*)(["”])$/s, "$2")
|
|
60
|
+
.replace(/\s+/g, " ");
|
|
61
|
+
const characters = Array.from(normalized);
|
|
62
|
+
if (characters.length <= 50) {
|
|
63
|
+
return normalized || "Image generation";
|
|
64
|
+
}
|
|
65
|
+
return `${characters.slice(0, 47).join("").trimEnd()}...`;
|
|
66
|
+
}
|
|
67
|
+
export function getImageModelLocalTitle(input, init) {
|
|
68
|
+
const url = fetchInputToUrl(input);
|
|
69
|
+
if (!/\/models\/[^/:]*(?:image|imagen)[^/:]*:streamGenerateContent/i.test(url)) {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
const body = init?.body;
|
|
73
|
+
const bodyText = typeof body === "string"
|
|
74
|
+
? body
|
|
75
|
+
: body instanceof Uint8Array
|
|
76
|
+
? new TextDecoder().decode(body)
|
|
77
|
+
: "";
|
|
78
|
+
if (!bodyText) {
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
try {
|
|
82
|
+
const sourceText = getOpenCodeTitleSourceText(JSON.parse(bodyText));
|
|
83
|
+
return sourceText === undefined ? undefined : formatLocalImageTitle(sourceText);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return undefined;
|
|
34
87
|
}
|
|
35
|
-
return `agent/${crypto.randomUUID()}/${Date.now()}/${crypto.randomUUID()}/2`;
|
|
36
88
|
}
|
|
37
89
|
function getAgyMaxOutputTokens(model) {
|
|
38
90
|
const lower = model.toLowerCase();
|
|
39
|
-
if (lower === "gemini-3.5-flash-low"
|
|
91
|
+
if (lower === "gemini-3.5-flash-low"
|
|
92
|
+
|| lower === "gemini-3.5-flash-extra-low"
|
|
93
|
+
|| lower === "gemini-3-flash-agent"
|
|
94
|
+
|| lower === "gemini-3.6-flash-low"
|
|
95
|
+
|| lower === "gemini-3.6-flash-medium"
|
|
96
|
+
|| lower === "gemini-3.6-flash-high") {
|
|
40
97
|
return 65536;
|
|
41
98
|
}
|
|
42
99
|
if (lower === "gemini-3.1-pro-low" || lower === "gemini-pro-agent") {
|
|
@@ -45,6 +102,9 @@ function getAgyMaxOutputTokens(model) {
|
|
|
45
102
|
if (lower === "claude-sonnet-4-6" || lower === "claude-opus-4-6-thinking") {
|
|
46
103
|
return 64000;
|
|
47
104
|
}
|
|
105
|
+
if (lower === "gpt-oss-120b-medium") {
|
|
106
|
+
return 32768;
|
|
107
|
+
}
|
|
48
108
|
return undefined;
|
|
49
109
|
}
|
|
50
110
|
function applyAgyGenerationDefaults(model, generationConfig, headerStyle) {
|
|
@@ -93,9 +153,9 @@ function buildSignatureSessionKey(sessionId, model, conversationKey, projectKey)
|
|
|
93
153
|
const JSON_SCHEMA_TYPES = new Set(["boolean", "string", "number", "integer", "array", "object"]);
|
|
94
154
|
function thinkingSafeReplacer(key, value) {
|
|
95
155
|
if (key === "thinking" && typeof value === "object" && value !== null) {
|
|
96
|
-
// Preserve
|
|
156
|
+
// Preserve tool schemas before and after Gemini uppercases their type.
|
|
97
157
|
const rec = value;
|
|
98
|
-
if (typeof rec.type === "string" && JSON_SCHEMA_TYPES.has(rec.type)) {
|
|
158
|
+
if (typeof rec.type === "string" && JSON_SCHEMA_TYPES.has(rec.type.toLowerCase())) {
|
|
99
159
|
return value;
|
|
100
160
|
}
|
|
101
161
|
// Flatten any non-string, non-Schema thinking to empty string
|
|
@@ -349,6 +409,75 @@ function isValidRequestPart(part) {
|
|
|
349
409
|
Object.prototype.hasOwnProperty.call(record, "codeExecutionResult") ||
|
|
350
410
|
Object.prototype.hasOwnProperty.call(record, "thought"));
|
|
351
411
|
}
|
|
412
|
+
function stripCacheControlFromParts(parts) {
|
|
413
|
+
if (!Array.isArray(parts)) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
for (const part of parts) {
|
|
417
|
+
if (!part || typeof part !== "object" || Array.isArray(part)) {
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
const record = part;
|
|
421
|
+
delete record.cache_control;
|
|
422
|
+
delete record.cacheControl;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
function stripUnsupportedAntigravityFields(payload) {
|
|
426
|
+
delete payload.providerOptions;
|
|
427
|
+
delete payload.cached_content;
|
|
428
|
+
delete payload.cachedContent;
|
|
429
|
+
delete payload.cache_control;
|
|
430
|
+
delete payload.cacheControl;
|
|
431
|
+
const extraBody = payload.extra_body;
|
|
432
|
+
if (extraBody && typeof extraBody === "object" && !Array.isArray(extraBody)) {
|
|
433
|
+
const extraBodyRecord = extraBody;
|
|
434
|
+
delete extraBodyRecord.cached_content;
|
|
435
|
+
delete extraBodyRecord.cachedContent;
|
|
436
|
+
delete extraBodyRecord.cache_control;
|
|
437
|
+
delete extraBodyRecord.cacheControl;
|
|
438
|
+
if (Object.keys(extraBodyRecord).length === 0) {
|
|
439
|
+
delete payload.extra_body;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
const stripContentParts = (items) => {
|
|
443
|
+
if (!Array.isArray(items)) {
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
for (const item of items) {
|
|
447
|
+
if (!item || typeof item !== "object" || Array.isArray(item)) {
|
|
448
|
+
continue;
|
|
449
|
+
}
|
|
450
|
+
const record = item;
|
|
451
|
+
stripCacheControlFromParts(record.parts);
|
|
452
|
+
stripCacheControlFromParts(record.content);
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
stripContentParts(payload.contents);
|
|
456
|
+
stripContentParts(payload.messages);
|
|
457
|
+
for (const instructionKey of ["systemInstruction", "system_instruction"]) {
|
|
458
|
+
const instruction = payload[instructionKey];
|
|
459
|
+
if (instruction && typeof instruction === "object" && !Array.isArray(instruction)) {
|
|
460
|
+
stripCacheControlFromParts(instruction.parts);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
function configureAntigravityToolCalling(payload) {
|
|
465
|
+
if (!Array.isArray(payload.tools) || payload.tools.length === 0) {
|
|
466
|
+
delete payload.toolConfig;
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
const toolConfig = payload.toolConfig && typeof payload.toolConfig === "object" && !Array.isArray(payload.toolConfig)
|
|
470
|
+
? payload.toolConfig
|
|
471
|
+
: {};
|
|
472
|
+
const functionCallingConfig = toolConfig.functionCallingConfig &&
|
|
473
|
+
typeof toolConfig.functionCallingConfig === "object" &&
|
|
474
|
+
!Array.isArray(toolConfig.functionCallingConfig)
|
|
475
|
+
? toolConfig.functionCallingConfig
|
|
476
|
+
: {};
|
|
477
|
+
functionCallingConfig.mode = "VALIDATED";
|
|
478
|
+
toolConfig.functionCallingConfig = functionCallingConfig;
|
|
479
|
+
payload.toolConfig = toolConfig;
|
|
480
|
+
}
|
|
352
481
|
function sanitizeRequestPayloadForAntigravity(payload) {
|
|
353
482
|
const anyPayload = payload;
|
|
354
483
|
if (Array.isArray(anyPayload.contents)) {
|
|
@@ -690,20 +819,27 @@ let _lastCacheStats = null;
|
|
|
690
819
|
export function getLastCacheStats() {
|
|
691
820
|
return _lastCacheStats;
|
|
692
821
|
}
|
|
693
|
-
function generateSyntheticProjectId() {
|
|
694
|
-
const adjectives = ["useful", "bright", "swift", "calm", "bold"];
|
|
695
|
-
const nouns = ["fuze", "wave", "spark", "flow", "core"];
|
|
696
|
-
const adj = adjectives[Math.floor(Math.random() * adjectives.length)];
|
|
697
|
-
const noun = nouns[Math.floor(Math.random() * nouns.length)];
|
|
698
|
-
const randomPart = crypto.randomUUID().slice(0, 5).toLowerCase();
|
|
699
|
-
return `${adj}-${noun}-${randomPart}`;
|
|
700
|
-
}
|
|
701
822
|
const STREAM_ACTION = "streamGenerateContent";
|
|
702
823
|
/**
|
|
703
|
-
*
|
|
824
|
+
* Extract a URL string from any fetch() input shape (string, URL, or Request).
|
|
825
|
+
*/
|
|
826
|
+
export function fetchInputToUrl(input) {
|
|
827
|
+
if (typeof input === "string")
|
|
828
|
+
return input;
|
|
829
|
+
if (input instanceof URL)
|
|
830
|
+
return input.href;
|
|
831
|
+
// Request-like object
|
|
832
|
+
const url = input.url;
|
|
833
|
+
return typeof url === "string" ? url : String(input);
|
|
834
|
+
}
|
|
835
|
+
/**
|
|
836
|
+
* Detects requests headed to the Google Generative Language API so we can
|
|
837
|
+
* intercept them. Handles string, URL, and Request inputs — matching on URL
|
|
838
|
+
* only would let `fetch(new Request(...))` / `fetch(new URL(...))` bypass the
|
|
839
|
+
* interceptor entirely.
|
|
704
840
|
*/
|
|
705
841
|
export function isGenerativeLanguageRequest(input) {
|
|
706
|
-
return
|
|
842
|
+
return fetchInputToUrl(input).includes("generativelanguage.googleapis.com");
|
|
707
843
|
}
|
|
708
844
|
export function prepareAntigravityRequest(input, init, accessToken, projectId, endpointOverride, headerStyle = "antigravity", forceThinkingRecovery = false, options) {
|
|
709
845
|
const baseInit = { ...init };
|
|
@@ -727,11 +863,14 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
|
|
|
727
863
|
headers.delete("x-api-key");
|
|
728
864
|
headers.delete("x-goog-api-key");
|
|
729
865
|
headers.delete("x-session-affinity");
|
|
866
|
+
headers.delete("x-session-id");
|
|
867
|
+
headers.delete("x-parent-session-id");
|
|
730
868
|
// Strip x-goog-user-project header to prevent 403 auth/license conflicts.
|
|
731
869
|
// This header is added by OpenCode/AI SDK and can force project-level checks
|
|
732
870
|
// that are not required for Antigravity/Gemini CLI OAuth requests.
|
|
733
871
|
headers.delete("x-goog-user-project");
|
|
734
|
-
const
|
|
872
|
+
const urlString = fetchInputToUrl(input);
|
|
873
|
+
const match = urlString.match(/\/models\/([^:]+):(\w+)/);
|
|
735
874
|
if (!match) {
|
|
736
875
|
return {
|
|
737
876
|
request: input,
|
|
@@ -766,9 +905,6 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
|
|
|
766
905
|
model: effectiveModel,
|
|
767
906
|
};
|
|
768
907
|
if (headerStyle === "antigravity") {
|
|
769
|
-
if (typeof wrappedBody.requestId !== "string" || !wrappedBody.requestId) {
|
|
770
|
-
wrappedBody.requestId = buildAntigravityRequestId("agent");
|
|
771
|
-
}
|
|
772
908
|
if (typeof wrappedBody.userAgent !== "string" || !wrappedBody.userAgent) {
|
|
773
909
|
wrappedBody.userAgent = "antigravity";
|
|
774
910
|
}
|
|
@@ -797,8 +933,6 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
|
|
|
797
933
|
sessionId = signatureSessionKey;
|
|
798
934
|
}
|
|
799
935
|
for (const req of requestObjects) {
|
|
800
|
-
// Use stable session ID for signature caching across multi-turn conversations
|
|
801
|
-
req.sessionId = signatureSessionKey;
|
|
802
936
|
stripInjectedDebugFromRequestPayload(req);
|
|
803
937
|
if (isClaude) {
|
|
804
938
|
// Step 0: Sanitize cross-model metadata (strips Gemini signatures when sending to Claude)
|
|
@@ -815,6 +949,11 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
|
|
|
815
949
|
// Step 3: Apply tool pairing fixes (ID assignment, response matching, orphan recovery)
|
|
816
950
|
applyToolPairingFixes(req, true);
|
|
817
951
|
}
|
|
952
|
+
if (headerStyle === "antigravity") {
|
|
953
|
+
sanitizeRequestPayloadForAntigravity(req);
|
|
954
|
+
stripUnsupportedAntigravityFields(req);
|
|
955
|
+
configureAntigravityToolCalling(req);
|
|
956
|
+
}
|
|
818
957
|
}
|
|
819
958
|
// Guard against assistant prefill: Claude rejects conversations ending
|
|
820
959
|
// with model/assistant messages. After context compaction, the conversation
|
|
@@ -845,15 +984,41 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
|
|
|
845
984
|
const hasCachedThinking = defaultSignatureStore.has(signatureSessionKey);
|
|
846
985
|
needsSignedThinkingWarmup = hasToolUse && !hasSignedThinking && !hasCachedThinking;
|
|
847
986
|
}
|
|
987
|
+
const wireRequest = requestObjects.at(-1);
|
|
988
|
+
if (wireRequest) {
|
|
989
|
+
if (headerStyle === "antigravity") {
|
|
990
|
+
const metadata = buildAgyAgentRequestMetadata(options?.agySession ?? DEFAULT_AGY_REQUEST_SESSION, wireRequest, effectiveModel, options?.agyRequestTimestamp);
|
|
991
|
+
wrappedBody.requestId = metadata.requestId;
|
|
992
|
+
wireRequest.sessionId = metadata.sessionId;
|
|
993
|
+
wireRequest.labels = metadata.labels;
|
|
994
|
+
orderAgyRequestPayloadInPlace(wireRequest);
|
|
995
|
+
}
|
|
996
|
+
else {
|
|
997
|
+
wireRequest.sessionId = signatureSessionKey;
|
|
998
|
+
}
|
|
999
|
+
}
|
|
848
1000
|
body = safeStringify(headerStyle === "antigravity" ? orderAntigravityEnvelope(wrappedBody) : wrappedBody);
|
|
849
1001
|
}
|
|
850
1002
|
else {
|
|
851
1003
|
const requestPayload = { ...parsedBody };
|
|
1004
|
+
if (headerStyle === "antigravity" &&
|
|
1005
|
+
isImageGenerationModel(effectiveModel) &&
|
|
1006
|
+
isOpenCodeTitleGenerationRequest(requestPayload)) {
|
|
1007
|
+
// OpenCode runs title generation through the active model. Route that
|
|
1008
|
+
// text-only helper call away from image generation to avoid consuming
|
|
1009
|
+
// image quota and writing unrelated image files.
|
|
1010
|
+
effectiveModel = "gemini-3.5-flash-low";
|
|
1011
|
+
tierThinkingBudget = 4000;
|
|
1012
|
+
tierThinkingLevel = undefined;
|
|
1013
|
+
}
|
|
852
1014
|
const rawGenerationConfig = requestPayload.generationConfig;
|
|
853
1015
|
const extraBody = requestPayload.extra_body;
|
|
854
1016
|
const variantConfig = extractVariantThinkingConfig(requestPayload.providerOptions, rawGenerationConfig);
|
|
855
1017
|
const isGemini3 = effectiveModel.toLowerCase().includes("gemini-3");
|
|
856
1018
|
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)}`);
|
|
1019
|
+
// providerOptions belongs to the host AI SDK and is only used above to
|
|
1020
|
+
// resolve the requested variant. It is never part of the Google wire schema.
|
|
1021
|
+
delete requestPayload.providerOptions;
|
|
857
1022
|
if (variantConfig?.thinkingLevel && isGemini3) {
|
|
858
1023
|
// Gemini 3 native format - use thinkingLevel directly
|
|
859
1024
|
const variantModelBase = rawModel
|
|
@@ -879,20 +1044,6 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
|
|
|
879
1044
|
tierThinkingLevel = undefined;
|
|
880
1045
|
}
|
|
881
1046
|
}
|
|
882
|
-
if (isClaude) {
|
|
883
|
-
if (!requestPayload.toolConfig) {
|
|
884
|
-
requestPayload.toolConfig = {};
|
|
885
|
-
}
|
|
886
|
-
if (typeof requestPayload.toolConfig === "object" && requestPayload.toolConfig !== null) {
|
|
887
|
-
const toolConfig = requestPayload.toolConfig;
|
|
888
|
-
if (!toolConfig.functionCallingConfig) {
|
|
889
|
-
toolConfig.functionCallingConfig = {};
|
|
890
|
-
}
|
|
891
|
-
if (typeof toolConfig.functionCallingConfig === "object" && toolConfig.functionCallingConfig !== null) {
|
|
892
|
-
toolConfig.functionCallingConfig.mode = "VALIDATED";
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
1047
|
// Resolve thinking configuration based on user settings and model capabilities
|
|
897
1048
|
// Image generation models don't support thinking - skip thinking config entirely
|
|
898
1049
|
const isImageModel = isImageGenerationModel(effectiveModel);
|
|
@@ -1011,25 +1162,27 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
|
|
|
1011
1162
|
requestPayload.systemInstruction = requestPayload.system_instruction;
|
|
1012
1163
|
delete requestPayload.system_instruction;
|
|
1013
1164
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1165
|
+
if (headerStyle !== "antigravity") {
|
|
1166
|
+
// Gemini CLI accepts explicit cachedContent references. Normalize its
|
|
1167
|
+
// snake_case aliases only on that transport; agy relies on implicit
|
|
1168
|
+
// prefix caching and does not send any of these fields.
|
|
1169
|
+
const cachedContentFromExtra = typeof requestPayload.extra_body === "object" && requestPayload.extra_body
|
|
1170
|
+
? requestPayload.extra_body.cached_content ??
|
|
1171
|
+
requestPayload.extra_body.cachedContent
|
|
1172
|
+
: undefined;
|
|
1173
|
+
const cachedContent = requestPayload.cached_content ??
|
|
1174
|
+
requestPayload.cachedContent ??
|
|
1175
|
+
cachedContentFromExtra;
|
|
1176
|
+
if (cachedContent) {
|
|
1177
|
+
requestPayload.cachedContent = cachedContent;
|
|
1178
|
+
}
|
|
1179
|
+
delete requestPayload.cached_content;
|
|
1180
|
+
if (requestPayload.extra_body && typeof requestPayload.extra_body === "object") {
|
|
1181
|
+
delete requestPayload.extra_body.cached_content;
|
|
1182
|
+
delete requestPayload.extra_body.cachedContent;
|
|
1183
|
+
if (Object.keys(requestPayload.extra_body).length === 0) {
|
|
1184
|
+
delete requestPayload.extra_body;
|
|
1185
|
+
}
|
|
1033
1186
|
}
|
|
1034
1187
|
}
|
|
1035
1188
|
// Normalize tools. For Claude models, keep full function declarations (names + schemas).
|
|
@@ -1309,13 +1462,30 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
|
|
|
1309
1462
|
}
|
|
1310
1463
|
stripInjectedDebugFromRequestPayload(requestPayload);
|
|
1311
1464
|
sanitizeRequestPayloadForAntigravity(requestPayload);
|
|
1312
|
-
|
|
1465
|
+
if (headerStyle === "antigravity") {
|
|
1466
|
+
stripUnsupportedAntigravityFields(requestPayload);
|
|
1467
|
+
configureAntigravityToolCalling(requestPayload);
|
|
1468
|
+
}
|
|
1469
|
+
// Use the stable default project ID (never a per-request random one):
|
|
1470
|
+
// a fresh random project each request busts the prompt cache and
|
|
1471
|
+
// fragments server-side quota/session state. ensureProjectContext
|
|
1472
|
+
// already floors empty cases to this default; this is defense in depth.
|
|
1473
|
+
const effectiveProjectId = projectId?.trim() || (headerStyle === "antigravity" ? ANTIGRAVITY_DEFAULT_PROJECT_ID : "");
|
|
1313
1474
|
resolvedProjectId = effectiveProjectId;
|
|
1314
|
-
//
|
|
1475
|
+
// Keep internal signature-cache identity separate from AGY wire session metadata.
|
|
1476
|
+
sessionId = signatureSessionKey;
|
|
1477
|
+
const agyMetadata = headerStyle === "antigravity"
|
|
1478
|
+
? buildAgyAgentRequestMetadata(options?.agySession ?? DEFAULT_AGY_REQUEST_SESSION, requestPayload, effectiveModel, options?.agyRequestTimestamp)
|
|
1479
|
+
: null;
|
|
1480
|
+
requestPayload.sessionId = agyMetadata?.sessionId ?? signatureSessionKey;
|
|
1481
|
+
if (agyMetadata) {
|
|
1482
|
+
requestPayload.labels = agyMetadata.labels;
|
|
1483
|
+
orderAgyRequestPayloadInPlace(requestPayload);
|
|
1484
|
+
}
|
|
1315
1485
|
const wrappedBody = headerStyle === "antigravity"
|
|
1316
1486
|
? {
|
|
1317
1487
|
project: effectiveProjectId,
|
|
1318
|
-
requestId:
|
|
1488
|
+
requestId: agyMetadata.requestId,
|
|
1319
1489
|
request: requestPayload,
|
|
1320
1490
|
model: effectiveModel,
|
|
1321
1491
|
userAgent: "antigravity",
|
|
@@ -1326,11 +1496,6 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
|
|
|
1326
1496
|
model: effectiveModel,
|
|
1327
1497
|
request: requestPayload,
|
|
1328
1498
|
};
|
|
1329
|
-
if (wrappedBody.request && typeof wrappedBody.request === 'object') {
|
|
1330
|
-
// Use stable session ID for signature caching across multi-turn conversations
|
|
1331
|
-
sessionId = signatureSessionKey;
|
|
1332
|
-
wrappedBody.request.sessionId = signatureSessionKey;
|
|
1333
|
-
}
|
|
1334
1499
|
body = safeStringify(headerStyle === "antigravity" ? orderAntigravityEnvelope(wrappedBody) : wrappedBody);
|
|
1335
1500
|
}
|
|
1336
1501
|
}
|
|
@@ -1407,17 +1572,21 @@ export function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
|
|
|
1407
1572
|
return null;
|
|
1408
1573
|
}
|
|
1409
1574
|
const warmupPrompt = "Warmup request for thinking signature.";
|
|
1575
|
+
const wireModel = typeof parsed.model === "string" ? parsed.model : "claude-sonnet-4-6";
|
|
1576
|
+
const requestObjects = [];
|
|
1410
1577
|
const updateRequest = (req) => {
|
|
1411
1578
|
req.contents = [{ role: "user", parts: [{ text: warmupPrompt }] }];
|
|
1412
1579
|
delete req.tools;
|
|
1413
1580
|
delete req.toolConfig;
|
|
1414
1581
|
const generationConfig = (req.generationConfig ?? {});
|
|
1415
1582
|
generationConfig.thinkingConfig = {
|
|
1416
|
-
|
|
1417
|
-
|
|
1583
|
+
includeThoughts: true,
|
|
1584
|
+
thinkingBudget: AGY_CLAUDE_THINKING_BUDGET,
|
|
1418
1585
|
};
|
|
1419
|
-
generationConfig.maxOutputTokens =
|
|
1586
|
+
generationConfig.maxOutputTokens = getAgyMaxOutputTokens(wireModel) ??
|
|
1587
|
+
computeClaudeMaxOutputTokens(AGY_CLAUDE_THINKING_BUDGET);
|
|
1420
1588
|
req.generationConfig = generationConfig;
|
|
1589
|
+
requestObjects.push(req);
|
|
1421
1590
|
};
|
|
1422
1591
|
if (parsed.request && typeof parsed.request === "object") {
|
|
1423
1592
|
updateRequest(parsed.request);
|
|
@@ -1429,6 +1598,22 @@ export function buildThinkingWarmupBody(bodyText, isClaudeThinking) {
|
|
|
1429
1598
|
else {
|
|
1430
1599
|
updateRequest(parsed);
|
|
1431
1600
|
}
|
|
1601
|
+
const wireRequest = requestObjects.at(-1);
|
|
1602
|
+
if (wireRequest) {
|
|
1603
|
+
const numericSessionId = typeof wireRequest.sessionId === "string"
|
|
1604
|
+
? wireRequest.sessionId
|
|
1605
|
+
: DEFAULT_AGY_REQUEST_SESSION.numericSessionId;
|
|
1606
|
+
const warmupSession = {
|
|
1607
|
+
conversationId: crypto.randomUUID(),
|
|
1608
|
+
trajectoryId: crypto.randomUUID(),
|
|
1609
|
+
numericSessionId,
|
|
1610
|
+
};
|
|
1611
|
+
const metadata = buildAgyAgentRequestMetadata(warmupSession, wireRequest, wireModel);
|
|
1612
|
+
parsed.requestId = metadata.requestId;
|
|
1613
|
+
wireRequest.sessionId = metadata.sessionId;
|
|
1614
|
+
wireRequest.labels = metadata.labels;
|
|
1615
|
+
orderAgyRequestPayloadInPlace(wireRequest);
|
|
1616
|
+
}
|
|
1432
1617
|
return safeStringify(parsed);
|
|
1433
1618
|
}
|
|
1434
1619
|
/**
|
|
@@ -1649,7 +1834,6 @@ export const __testExports = {
|
|
|
1649
1834
|
hasToolUseInMessages,
|
|
1650
1835
|
ensureThinkingBeforeToolUseInContents,
|
|
1651
1836
|
ensureThinkingBeforeToolUseInMessages,
|
|
1652
|
-
generateSyntheticProjectId,
|
|
1653
1837
|
MIN_SIGNATURE_LENGTH,
|
|
1654
1838
|
transformSseLine,
|
|
1655
1839
|
transformStreamingPayload,
|