opencode-antigravity-auth 1.2.0 → 1.2.2

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.
Files changed (48) hide show
  1. package/README.md +212 -98
  2. package/dist/src/constants.d.ts +6 -0
  3. package/dist/src/constants.d.ts.map +1 -1
  4. package/dist/src/constants.js +5 -0
  5. package/dist/src/constants.js.map +1 -1
  6. package/dist/src/hooks/auto-update-checker/cache.d.ts +3 -0
  7. package/dist/src/hooks/auto-update-checker/cache.d.ts.map +1 -0
  8. package/dist/src/hooks/auto-update-checker/cache.js +71 -0
  9. package/dist/src/hooks/auto-update-checker/cache.js.map +1 -0
  10. package/dist/src/hooks/auto-update-checker/checker.d.ts +16 -0
  11. package/dist/src/hooks/auto-update-checker/checker.d.ts.map +1 -0
  12. package/dist/src/hooks/auto-update-checker/checker.js +237 -0
  13. package/dist/src/hooks/auto-update-checker/checker.js.map +1 -0
  14. package/dist/src/hooks/auto-update-checker/constants.d.ts +9 -0
  15. package/dist/src/hooks/auto-update-checker/constants.d.ts.map +1 -0
  16. package/dist/src/hooks/auto-update-checker/constants.js +23 -0
  17. package/dist/src/hooks/auto-update-checker/constants.js.map +1 -0
  18. package/dist/src/hooks/auto-update-checker/index.d.ts +34 -0
  19. package/dist/src/hooks/auto-update-checker/index.d.ts.map +1 -0
  20. package/dist/src/hooks/auto-update-checker/index.js +121 -0
  21. package/dist/src/hooks/auto-update-checker/index.js.map +1 -0
  22. package/dist/src/hooks/auto-update-checker/types.d.ts +25 -0
  23. package/dist/src/hooks/auto-update-checker/types.d.ts.map +1 -0
  24. package/dist/src/hooks/auto-update-checker/types.js +1 -0
  25. package/dist/src/hooks/auto-update-checker/types.js.map +1 -0
  26. package/dist/src/plugin/accounts.d.ts +25 -11
  27. package/dist/src/plugin/accounts.d.ts.map +1 -1
  28. package/dist/src/plugin/accounts.js +161 -55
  29. package/dist/src/plugin/accounts.js.map +1 -1
  30. package/dist/src/plugin/debug.d.ts +32 -0
  31. package/dist/src/plugin/debug.d.ts.map +1 -1
  32. package/dist/src/plugin/debug.js +140 -12
  33. package/dist/src/plugin/debug.js.map +1 -1
  34. package/dist/src/plugin/request.d.ts +6 -2
  35. package/dist/src/plugin/request.d.ts.map +1 -1
  36. package/dist/src/plugin/request.js +361 -21
  37. package/dist/src/plugin/request.js.map +1 -1
  38. package/dist/src/plugin/storage.d.ts +52 -9
  39. package/dist/src/plugin/storage.d.ts.map +1 -1
  40. package/dist/src/plugin/storage.js +91 -10
  41. package/dist/src/plugin/storage.js.map +1 -1
  42. package/dist/src/plugin/types.d.ts +8 -0
  43. package/dist/src/plugin/types.d.ts.map +1 -1
  44. package/dist/src/plugin.d.ts +3 -3
  45. package/dist/src/plugin.d.ts.map +1 -1
  46. package/dist/src/plugin.js +865 -486
  47. package/dist/src/plugin.js.map +1 -1
  48. package/package.json +1 -1
@@ -1,8 +1,8 @@
1
1
  import crypto from "node:crypto";
2
- import { ANTIGRAVITY_HEADERS, ANTIGRAVITY_ENDPOINT, } from "../constants";
2
+ import { ANTIGRAVITY_HEADERS, GEMINI_CLI_HEADERS, ANTIGRAVITY_ENDPOINT, } from "../constants";
3
3
  import { cacheSignature, getCachedSignature } from "./cache";
4
- import { logAntigravityDebugResponse } from "./debug";
5
- import { extractThinkingConfig, extractUsageFromSsePayload, extractUsageMetadata, filterUnsignedThinkingBlocks, filterMessagesThinkingBlocks, isThinkingCapableModel, normalizeThinkingConfig, parseAntigravityApiBody, resolveThinkingConfig, rewriteAntigravityPreviewAccessError, transformThinkingParts, } from "./request-helpers";
4
+ import { DEBUG_MESSAGE_PREFIX, isDebugEnabled, logAntigravityDebugResponse, } from "./debug";
5
+ import { DEFAULT_THINKING_BUDGET, extractThinkingConfig, extractUsageFromSsePayload, extractUsageMetadata, filterUnsignedThinkingBlocks, filterMessagesThinkingBlocks, isThinkingCapableModel, normalizeThinkingConfig, parseAntigravityApiBody, resolveThinkingConfig, rewriteAntigravityPreviewAccessError, transformThinkingParts, } from "./request-helpers";
6
6
  /**
7
7
  * Stable session ID for the plugin's lifetime.
8
8
  * This is used for caching thinking signatures across multi-turn conversations.
@@ -11,6 +11,257 @@ import { extractThinkingConfig, extractUsageFromSsePayload, extractUsageMetadata
11
11
  const PLUGIN_SESSION_ID = `-${crypto.randomUUID()}`;
12
12
  // Claude thinking models need a sufficiently large max output token limit when thinking is enabled.
13
13
  const CLAUDE_THINKING_MAX_OUTPUT_TOKENS = 64_000;
14
+ const MIN_SIGNATURE_LENGTH = 50;
15
+ const lastSignedThinkingBySessionId = new Map();
16
+ function formatDebugLinesForThinking(lines) {
17
+ const cleaned = lines
18
+ .map((line) => line.trim())
19
+ .filter((line) => line.length > 0)
20
+ .slice(-50);
21
+ return `${DEBUG_MESSAGE_PREFIX}\n${cleaned.map((line) => `- ${line}`).join("\n")}`;
22
+ }
23
+ function injectDebugThinking(response, debugText) {
24
+ if (!response || typeof response !== "object") {
25
+ return response;
26
+ }
27
+ const resp = response;
28
+ if (Array.isArray(resp.candidates) && resp.candidates.length > 0) {
29
+ const candidates = resp.candidates.slice();
30
+ const first = candidates[0];
31
+ if (first &&
32
+ typeof first === "object" &&
33
+ first.content &&
34
+ typeof first.content === "object" &&
35
+ Array.isArray(first.content.parts)) {
36
+ const parts = [{ thought: true, text: debugText }, ...first.content.parts];
37
+ candidates[0] = { ...first, content: { ...first.content, parts } };
38
+ return { ...resp, candidates };
39
+ }
40
+ return resp;
41
+ }
42
+ if (Array.isArray(resp.content)) {
43
+ const content = [{ type: "thinking", thinking: debugText }, ...resp.content];
44
+ return { ...resp, content };
45
+ }
46
+ if (!resp.reasoning_content) {
47
+ return { ...resp, reasoning_content: debugText };
48
+ }
49
+ return resp;
50
+ }
51
+ function stripInjectedDebugFromParts(parts) {
52
+ if (!Array.isArray(parts)) {
53
+ return parts;
54
+ }
55
+ return parts.filter((part) => {
56
+ if (!part || typeof part !== "object") {
57
+ return true;
58
+ }
59
+ const record = part;
60
+ const text = typeof record.text === "string"
61
+ ? record.text
62
+ : typeof record.thinking === "string"
63
+ ? record.thinking
64
+ : undefined;
65
+ if (text && text.startsWith(DEBUG_MESSAGE_PREFIX)) {
66
+ return false;
67
+ }
68
+ return true;
69
+ });
70
+ }
71
+ function stripInjectedDebugFromRequestPayload(payload) {
72
+ const anyPayload = payload;
73
+ if (Array.isArray(anyPayload.contents)) {
74
+ anyPayload.contents = anyPayload.contents.map((content) => {
75
+ if (!content || typeof content !== "object") {
76
+ return content;
77
+ }
78
+ if (Array.isArray(content.parts)) {
79
+ return { ...content, parts: stripInjectedDebugFromParts(content.parts) };
80
+ }
81
+ if (Array.isArray(content.content)) {
82
+ return { ...content, content: stripInjectedDebugFromParts(content.content) };
83
+ }
84
+ return content;
85
+ });
86
+ }
87
+ if (Array.isArray(anyPayload.messages)) {
88
+ anyPayload.messages = anyPayload.messages.map((message) => {
89
+ if (!message || typeof message !== "object") {
90
+ return message;
91
+ }
92
+ if (Array.isArray(message.content)) {
93
+ return { ...message, content: stripInjectedDebugFromParts(message.content) };
94
+ }
95
+ return message;
96
+ });
97
+ }
98
+ }
99
+ function isGeminiToolUsePart(part) {
100
+ return !!(part && typeof part === "object" && (part.functionCall || part.tool_use || part.toolUse));
101
+ }
102
+ function isGeminiThinkingPart(part) {
103
+ return !!(part &&
104
+ typeof part === "object" &&
105
+ (part.thought === true || part.type === "thinking" || part.type === "reasoning"));
106
+ }
107
+ function ensureThoughtSignature(part, sessionId) {
108
+ if (!part || typeof part !== "object") {
109
+ return part;
110
+ }
111
+ const text = typeof part.text === "string" ? part.text : typeof part.thinking === "string" ? part.thinking : "";
112
+ if (!text) {
113
+ return part;
114
+ }
115
+ if (part.thought === true) {
116
+ if (!part.thoughtSignature) {
117
+ const cached = getCachedSignature(sessionId, text);
118
+ if (cached) {
119
+ return { ...part, thoughtSignature: cached };
120
+ }
121
+ }
122
+ return part;
123
+ }
124
+ if ((part.type === "thinking" || part.type === "reasoning") && !part.signature) {
125
+ const cached = getCachedSignature(sessionId, text);
126
+ if (cached) {
127
+ return { ...part, signature: cached };
128
+ }
129
+ }
130
+ return part;
131
+ }
132
+ function hasSignedThinkingPart(part) {
133
+ if (!part || typeof part !== "object") {
134
+ return false;
135
+ }
136
+ if (part.thought === true) {
137
+ return typeof part.thoughtSignature === "string" && part.thoughtSignature.length >= MIN_SIGNATURE_LENGTH;
138
+ }
139
+ if (part.type === "thinking" || part.type === "reasoning") {
140
+ return typeof part.signature === "string" && part.signature.length >= MIN_SIGNATURE_LENGTH;
141
+ }
142
+ return false;
143
+ }
144
+ function ensureThinkingBeforeToolUseInContents(contents, sessionId) {
145
+ return contents.map((content) => {
146
+ if (!content || typeof content !== "object" || !Array.isArray(content.parts)) {
147
+ return content;
148
+ }
149
+ const role = content.role;
150
+ if (role !== "model" && role !== "assistant") {
151
+ return content;
152
+ }
153
+ const parts = content.parts;
154
+ const hasToolUse = parts.some(isGeminiToolUsePart);
155
+ if (!hasToolUse) {
156
+ return content;
157
+ }
158
+ const thinkingParts = parts.filter(isGeminiThinkingPart).map((p) => ensureThoughtSignature(p, sessionId));
159
+ const otherParts = parts.filter((p) => !isGeminiThinkingPart(p));
160
+ const hasSignedThinking = thinkingParts.some(hasSignedThinkingPart);
161
+ if (hasSignedThinking) {
162
+ return { ...content, parts: [...thinkingParts, ...otherParts] };
163
+ }
164
+ const lastThinking = lastSignedThinkingBySessionId.get(sessionId);
165
+ if (!lastThinking) {
166
+ return content;
167
+ }
168
+ const injected = {
169
+ thought: true,
170
+ text: lastThinking.text,
171
+ thoughtSignature: lastThinking.signature,
172
+ };
173
+ return { ...content, parts: [injected, ...otherParts] };
174
+ });
175
+ }
176
+ function ensureMessageThinkingSignature(block, sessionId) {
177
+ if (!block || typeof block !== "object") {
178
+ return block;
179
+ }
180
+ if (block.type !== "thinking" && block.type !== "redacted_thinking") {
181
+ return block;
182
+ }
183
+ if (typeof block.signature === "string" && block.signature.length >= MIN_SIGNATURE_LENGTH) {
184
+ return block;
185
+ }
186
+ const text = typeof block.thinking === "string" ? block.thinking : typeof block.text === "string" ? block.text : "";
187
+ if (!text) {
188
+ return block;
189
+ }
190
+ const cached = getCachedSignature(sessionId, text);
191
+ if (cached) {
192
+ return { ...block, signature: cached };
193
+ }
194
+ return block;
195
+ }
196
+ function hasToolUseInContents(contents) {
197
+ return contents.some((content) => {
198
+ if (!content || typeof content !== "object" || !Array.isArray(content.parts)) {
199
+ return false;
200
+ }
201
+ return content.parts.some(isGeminiToolUsePart);
202
+ });
203
+ }
204
+ function hasSignedThinkingInContents(contents) {
205
+ return contents.some((content) => {
206
+ if (!content || typeof content !== "object" || !Array.isArray(content.parts)) {
207
+ return false;
208
+ }
209
+ return content.parts.some(hasSignedThinkingPart);
210
+ });
211
+ }
212
+ function hasToolUseInMessages(messages) {
213
+ return messages.some((message) => {
214
+ if (!message || typeof message !== "object" || !Array.isArray(message.content)) {
215
+ return false;
216
+ }
217
+ return message.content.some((block) => block && typeof block === "object" && (block.type === "tool_use" || block.type === "tool_result"));
218
+ });
219
+ }
220
+ function hasSignedThinkingInMessages(messages) {
221
+ return messages.some((message) => {
222
+ if (!message || typeof message !== "object" || !Array.isArray(message.content)) {
223
+ return false;
224
+ }
225
+ return message.content.some((block) => block &&
226
+ typeof block === "object" &&
227
+ (block.type === "thinking" || block.type === "redacted_thinking") &&
228
+ typeof block.signature === "string" &&
229
+ block.signature.length >= MIN_SIGNATURE_LENGTH);
230
+ });
231
+ }
232
+ function ensureThinkingBeforeToolUseInMessages(messages, sessionId) {
233
+ return messages.map((message) => {
234
+ if (!message || typeof message !== "object" || !Array.isArray(message.content)) {
235
+ return message;
236
+ }
237
+ if (message.role !== "assistant") {
238
+ return message;
239
+ }
240
+ const blocks = message.content;
241
+ const hasToolUse = blocks.some((b) => b && typeof b === "object" && (b.type === "tool_use" || b.type === "tool_result"));
242
+ if (!hasToolUse) {
243
+ return message;
244
+ }
245
+ const thinkingBlocks = blocks
246
+ .filter((b) => b && typeof b === "object" && (b.type === "thinking" || b.type === "redacted_thinking"))
247
+ .map((b) => ensureMessageThinkingSignature(b, sessionId));
248
+ const otherBlocks = blocks.filter((b) => !(b && typeof b === "object" && (b.type === "thinking" || b.type === "redacted_thinking")));
249
+ const hasSignedThinking = thinkingBlocks.some((b) => typeof b.signature === "string" && b.signature.length >= MIN_SIGNATURE_LENGTH);
250
+ if (hasSignedThinking) {
251
+ return { ...message, content: [...thinkingBlocks, ...otherBlocks] };
252
+ }
253
+ const lastThinking = lastSignedThinkingBySessionId.get(sessionId);
254
+ if (!lastThinking) {
255
+ return message;
256
+ }
257
+ const injected = {
258
+ type: "thinking",
259
+ thinking: lastThinking.text,
260
+ signature: lastThinking.signature,
261
+ };
262
+ return { ...message, content: [injected, ...otherBlocks] };
263
+ });
264
+ }
14
265
  /**
15
266
  * Gets the stable session ID for this plugin instance.
16
267
  */
@@ -64,12 +315,13 @@ function transformStreamingPayload(payload) {
64
315
  * transforming each line as it arrives for true real-time streaming support.
65
316
  * Optionally caches thinking signatures for Claude multi-turn conversations.
66
317
  */
67
- function createStreamingTransformer(sessionId) {
318
+ function createStreamingTransformer(sessionId, debugText) {
68
319
  const decoder = new TextDecoder();
69
320
  const encoder = new TextEncoder();
70
321
  let buffer = "";
71
322
  // Buffer for accumulating thinking text per candidate index (for signature caching)
72
323
  const thoughtBuffer = new Map();
324
+ const debugState = { injected: false };
73
325
  return new TransformStream({
74
326
  transform(chunk, controller) {
75
327
  // Decode chunk with stream: true to handle multi-byte characters correctly
@@ -80,7 +332,7 @@ function createStreamingTransformer(sessionId) {
80
332
  buffer = lines.pop() || "";
81
333
  for (const line of lines) {
82
334
  // Transform and forward each line immediately
83
- const transformedLine = transformSseLine(line, sessionId, thoughtBuffer);
335
+ const transformedLine = transformSseLine(line, sessionId, thoughtBuffer, debugText, debugState);
84
336
  controller.enqueue(encoder.encode(transformedLine + "\n"));
85
337
  }
86
338
  },
@@ -89,7 +341,7 @@ function createStreamingTransformer(sessionId) {
89
341
  buffer += decoder.decode();
90
342
  // Process any remaining data in buffer
91
343
  if (buffer) {
92
- const transformedLine = transformSseLine(buffer, sessionId, thoughtBuffer);
344
+ const transformedLine = transformSseLine(buffer, sessionId, thoughtBuffer, debugText, debugState);
93
345
  controller.enqueue(encoder.encode(transformedLine));
94
346
  }
95
347
  },
@@ -99,7 +351,7 @@ function createStreamingTransformer(sessionId) {
99
351
  * Transforms a single SSE line, extracting and transforming the inner response.
100
352
  * Optionally caches thinking signatures for Claude multi-turn support.
101
353
  */
102
- function transformSseLine(line, sessionId, thoughtBuffer) {
354
+ function transformSseLine(line, sessionId, thoughtBuffer, debugText, debugState) {
103
355
  if (!line.startsWith("data:")) {
104
356
  return line;
105
357
  }
@@ -110,11 +362,15 @@ function transformSseLine(line, sessionId, thoughtBuffer) {
110
362
  try {
111
363
  const parsed = JSON.parse(json);
112
364
  if (parsed.response !== undefined) {
113
- // Cache thinking signatures for Claude multi-turn support
114
365
  if (sessionId && thoughtBuffer) {
115
366
  cacheThinkingSignatures(parsed.response, sessionId, thoughtBuffer);
116
367
  }
117
- const transformed = transformThinkingParts(parsed.response);
368
+ let response = parsed.response;
369
+ if (debugText && debugState && !debugState.injected) {
370
+ response = injectDebugThinking(response, debugText);
371
+ debugState.injected = true;
372
+ }
373
+ const transformed = transformThinkingParts(response);
118
374
  return `data: ${JSON.stringify(transformed)}`;
119
375
  }
120
376
  }
@@ -147,6 +403,7 @@ function cacheThinkingSignatures(response, sessionId, thoughtBuffer) {
147
403
  const fullText = thoughtBuffer.get(index) ?? "";
148
404
  if (fullText && sessionId) {
149
405
  cacheSignature(sessionId, fullText, part.thoughtSignature);
406
+ lastSignedThinkingBySessionId.set(sessionId, { text: fullText, signature: part.thoughtSignature });
150
407
  }
151
408
  }
152
409
  });
@@ -161,6 +418,7 @@ function cacheThinkingSignatures(response, sessionId, thoughtBuffer) {
161
418
  }
162
419
  if (block?.signature && thinkingText && sessionId) {
163
420
  cacheSignature(sessionId, thinkingText, block.signature);
421
+ lastSignedThinkingBySessionId.set(sessionId, { text: thinkingText, signature: block.signature });
164
422
  }
165
423
  });
166
424
  }
@@ -169,7 +427,7 @@ function cacheThinkingSignatures(response, sessionId, thoughtBuffer) {
169
427
  * Rewrites OpenAI-style requests into Antigravity shape, normalizing model, headers,
170
428
  * optional cached_content, and thinking config. Also toggles streaming mode for SSE actions.
171
429
  */
172
- export function prepareAntigravityRequest(input, init, accessToken, projectId, endpointOverride) {
430
+ export function prepareAntigravityRequest(input, init, accessToken, projectId, endpointOverride, headerStyle = "antigravity") {
173
431
  const baseInit = { ...init };
174
432
  const headers = new Headers(init?.headers ?? {});
175
433
  let resolvedProjectId = projectId?.trim() || "";
@@ -177,11 +435,13 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
177
435
  const toolDebugSummaries = [];
178
436
  let toolDebugPayload;
179
437
  let sessionId;
438
+ let needsSignedThinkingWarmup = false;
180
439
  if (!isGenerativeLanguageRequest(input)) {
181
440
  return {
182
441
  request: input,
183
442
  init: { ...baseInit, headers },
184
443
  streaming: false,
444
+ headerStyle,
185
445
  };
186
446
  }
187
447
  headers.set("Authorization", `Bearer ${accessToken}`);
@@ -192,11 +452,16 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
192
452
  request: input,
193
453
  init: { ...baseInit, headers },
194
454
  streaming: false,
455
+ headerStyle,
195
456
  };
196
457
  }
197
458
  const [, rawModel = "", rawAction = ""] = match;
198
- const effectiveModel = rawModel;
199
- const upstreamModel = rawModel;
459
+ const requestedModel = rawModel;
460
+ let upstreamModel = rawModel;
461
+ if (upstreamModel === "gemini-2.5-flash-image") {
462
+ upstreamModel = "gemini-2.5-flash";
463
+ }
464
+ const effectiveModel = upstreamModel;
200
465
  const streaming = rawAction === STREAM_ACTION;
201
466
  const baseEndpoint = endpointOverride ?? ANTIGRAVITY_ENDPOINT;
202
467
  const transformedUrl = `${baseEndpoint}/v1internal:${rawAction}${streaming ? "?alt=sse" : ""}`;
@@ -230,7 +495,14 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
230
495
  for (const req of requestObjects) {
231
496
  // Use stable session ID for signature caching across multi-turn conversations
232
497
  req.sessionId = PLUGIN_SESSION_ID;
498
+ stripInjectedDebugFromRequestPayload(req);
233
499
  if (isClaudeModel) {
500
+ if (isClaudeThinkingModel && Array.isArray(req.contents)) {
501
+ req.contents = ensureThinkingBeforeToolUseInContents(req.contents, PLUGIN_SESSION_ID);
502
+ }
503
+ if (isClaudeThinkingModel && Array.isArray(req.messages)) {
504
+ req.messages = ensureThinkingBeforeToolUseInMessages(req.messages, PLUGIN_SESSION_ID);
505
+ }
234
506
  if (Array.isArray(req.contents)) {
235
507
  req.contents = filterUnsignedThinkingBlocks(req.contents, PLUGIN_SESSION_ID, getCachedSignature);
236
508
  }
@@ -239,6 +511,14 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
239
511
  }
240
512
  }
241
513
  }
514
+ if (isClaudeThinkingModel && sessionId) {
515
+ const hasToolUse = requestObjects.some((req) => (Array.isArray(req.contents) && hasToolUseInContents(req.contents)) ||
516
+ (Array.isArray(req.messages) && hasToolUseInMessages(req.messages)));
517
+ const hasSignedThinking = requestObjects.some((req) => (Array.isArray(req.contents) && hasSignedThinkingInContents(req.contents)) ||
518
+ (Array.isArray(req.messages) && hasSignedThinkingInMessages(req.messages)));
519
+ const hasCachedThinking = lastSignedThinkingBySessionId.has(sessionId);
520
+ needsSignedThinkingWarmup = hasToolUse && !hasSignedThinking && !hasCachedThinking;
521
+ }
242
522
  body = JSON.stringify(wrappedBody);
243
523
  }
244
524
  else {
@@ -575,6 +855,21 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
575
855
  // Attempts to restore signatures from cache for multi-turn conversations
576
856
  // Handle both Gemini-style contents[] and Anthropic-style messages[] payloads.
577
857
  if (isClaudeModel) {
858
+ if (isClaudeThinkingModel && Array.isArray(requestPayload.contents)) {
859
+ requestPayload.contents = ensureThinkingBeforeToolUseInContents(requestPayload.contents, PLUGIN_SESSION_ID);
860
+ }
861
+ if (isClaudeThinkingModel && Array.isArray(requestPayload.messages)) {
862
+ requestPayload.messages = ensureThinkingBeforeToolUseInMessages(requestPayload.messages, PLUGIN_SESSION_ID);
863
+ }
864
+ if (isClaudeThinkingModel) {
865
+ const sessionKey = PLUGIN_SESSION_ID;
866
+ const hasToolUse = (Array.isArray(requestPayload.contents) && hasToolUseInContents(requestPayload.contents)) ||
867
+ (Array.isArray(requestPayload.messages) && hasToolUseInMessages(requestPayload.messages));
868
+ const hasSignedThinking = (Array.isArray(requestPayload.contents) && hasSignedThinkingInContents(requestPayload.contents)) ||
869
+ (Array.isArray(requestPayload.messages) && hasSignedThinkingInMessages(requestPayload.messages));
870
+ const hasCachedThinking = lastSignedThinkingBySessionId.has(sessionKey);
871
+ needsSignedThinkingWarmup = hasToolUse && !hasSignedThinking && !hasCachedThinking;
872
+ }
578
873
  if (Array.isArray(requestPayload.contents)) {
579
874
  requestPayload.contents = filterUnsignedThinkingBlocks(requestPayload.contents, PLUGIN_SESSION_ID, getCachedSignature);
580
875
  }
@@ -637,6 +932,7 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
637
932
  if ("model" in requestPayload) {
638
933
  delete requestPayload.model;
639
934
  }
935
+ stripInjectedDebugFromRequestPayload(requestPayload);
640
936
  const effectiveProjectId = projectId?.trim() || generateSyntheticProjectId();
641
937
  resolvedProjectId = effectiveProjectId;
642
938
  const wrappedBody = {
@@ -678,9 +974,10 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
678
974
  headers.set("anthropic-beta", interleavedHeader);
679
975
  }
680
976
  }
681
- headers.set("User-Agent", ANTIGRAVITY_HEADERS["User-Agent"]);
682
- headers.set("X-Goog-Api-Client", ANTIGRAVITY_HEADERS["X-Goog-Api-Client"]);
683
- headers.set("Client-Metadata", ANTIGRAVITY_HEADERS["Client-Metadata"]);
977
+ const selectedHeaders = headerStyle === "gemini-cli" ? GEMINI_CLI_HEADERS : ANTIGRAVITY_HEADERS;
978
+ headers.set("User-Agent", selectedHeaders["User-Agent"]);
979
+ headers.set("X-Goog-Api-Client", selectedHeaders["X-Goog-Api-Client"]);
980
+ headers.set("Client-Metadata", selectedHeaders["Client-Metadata"]);
684
981
  // Optional debug header to observe tool normalization on the backend if surfaced
685
982
  if (toolDebugMissing > 0) {
686
983
  headers.set("X-Opencode-Tools-Debug", String(toolDebugMissing));
@@ -693,7 +990,7 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
693
990
  body,
694
991
  },
695
992
  streaming,
696
- requestedModel: rawModel,
993
+ requestedModel,
697
994
  effectiveModel: upstreamModel,
698
995
  projectId: resolvedProjectId,
699
996
  endpoint: transformedUrl,
@@ -701,8 +998,46 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
701
998
  toolDebugMissing,
702
999
  toolDebugSummary: toolDebugSummaries.slice(0, 20).join(" | "),
703
1000
  toolDebugPayload,
1001
+ needsSignedThinkingWarmup,
1002
+ headerStyle,
704
1003
  };
705
1004
  }
1005
+ export function buildThinkingWarmupBody(bodyText, isClaudeThinkingModel) {
1006
+ if (!bodyText || !isClaudeThinkingModel) {
1007
+ return null;
1008
+ }
1009
+ let parsed;
1010
+ try {
1011
+ parsed = JSON.parse(bodyText);
1012
+ }
1013
+ catch {
1014
+ return null;
1015
+ }
1016
+ const warmupPrompt = "Warmup request for thinking signature.";
1017
+ const updateRequest = (req) => {
1018
+ req.contents = [{ role: "user", parts: [{ text: warmupPrompt }] }];
1019
+ delete req.tools;
1020
+ delete req.toolConfig;
1021
+ const generationConfig = (req.generationConfig ?? {});
1022
+ generationConfig.thinkingConfig = {
1023
+ include_thoughts: true,
1024
+ thinking_budget: DEFAULT_THINKING_BUDGET,
1025
+ };
1026
+ generationConfig.maxOutputTokens = CLAUDE_THINKING_MAX_OUTPUT_TOKENS;
1027
+ req.generationConfig = generationConfig;
1028
+ };
1029
+ if (parsed.request && typeof parsed.request === "object") {
1030
+ updateRequest(parsed.request);
1031
+ const nested = parsed.request.request;
1032
+ if (nested && typeof nested === "object") {
1033
+ updateRequest(nested);
1034
+ }
1035
+ }
1036
+ else {
1037
+ updateRequest(parsed);
1038
+ }
1039
+ return JSON.stringify(parsed);
1040
+ }
706
1041
  /**
707
1042
  * Normalizes Antigravity responses: applies retry headers, extracts cache usage into headers,
708
1043
  * rewrites preview errors, flattens streaming payloads, and logs debug metadata.
@@ -710,10 +1045,13 @@ export function prepareAntigravityRequest(input, init, accessToken, projectId, e
710
1045
  * For streaming SSE responses, uses TransformStream for true real-time incremental streaming.
711
1046
  * Thinking/reasoning tokens are transformed and forwarded immediately as they arrive.
712
1047
  */
713
- export async function transformAntigravityResponse(response, streaming, debugContext, requestedModel, projectId, endpoint, effectiveModel, sessionId, toolDebugMissing, toolDebugSummary, toolDebugPayload) {
1048
+ export async function transformAntigravityResponse(response, streaming, debugContext, requestedModel, projectId, endpoint, effectiveModel, sessionId, toolDebugMissing, toolDebugSummary, toolDebugPayload, debugLines) {
714
1049
  const contentType = response.headers.get("content-type") ?? "";
715
1050
  const isJsonResponse = contentType.includes("application/json");
716
1051
  const isEventStreamResponse = contentType.includes("text/event-stream");
1052
+ const debugText = isDebugEnabled() && Array.isArray(debugLines) && debugLines.length > 0
1053
+ ? formatDebugLinesForThinking(debugLines)
1054
+ : undefined;
717
1055
  if (!isJsonResponse && !isEventStreamResponse) {
718
1056
  logAntigravityDebugResponse(debugContext, response, {
719
1057
  note: "Non-JSON response (body omitted)",
@@ -730,7 +1068,7 @@ export async function transformAntigravityResponse(response, streaming, debugCon
730
1068
  });
731
1069
  // Use the optimized line-by-line transformer for immediate forwarding
732
1070
  // This ensures thinking/reasoning content streams in real-time
733
- return new Response(response.body.pipeThrough(createStreamingTransformer(sessionId)), {
1071
+ return new Response(response.body.pipeThrough(createStreamingTransformer(sessionId, debugText)), {
734
1072
  status: response.status,
735
1073
  statusText: response.statusText,
736
1074
  headers,
@@ -749,8 +1087,9 @@ export async function transformAntigravityResponse(response, streaming, debugCon
749
1087
  }
750
1088
  // Inject Debug Info
751
1089
  if (errorBody?.error) {
752
- 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}` : ""}`;
753
- errorBody.error.message = (errorBody.error.message || "Unknown error") + debugInfo;
1090
+ 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}` : ""}`;
1091
+ const injectedDebug = debugText ? `\n\n${debugText}` : "";
1092
+ errorBody.error.message = (errorBody.error.message || "Unknown error") + debugInfo + injectedDebug;
754
1093
  return new Response(JSON.stringify(errorBody), {
755
1094
  status: response.status,
756
1095
  statusText: response.statusText,
@@ -806,7 +1145,8 @@ export async function transformAntigravityResponse(response, streaming, debugCon
806
1145
  return new Response(text, init);
807
1146
  }
808
1147
  if (effectiveBody?.response !== undefined) {
809
- const transformed = transformThinkingParts(effectiveBody.response);
1148
+ const responseBody = debugText ? injectDebugThinking(effectiveBody.response, debugText) : effectiveBody.response;
1149
+ const transformed = transformThinkingParts(responseBody);
810
1150
  return new Response(JSON.stringify(transformed), init);
811
1151
  }
812
1152
  if (patched) {