Merge pull request #959 from rdev/rdev/finally-fix-antigravity-claude
Fix antigravity claude
This commit is contained in:
@@ -117,6 +117,7 @@
|
|||||||
- Logging: tolerate `EIO` from console writes to avoid gateway crashes. (#925, fixes #878) — thanks @grp06.
|
- Logging: tolerate `EIO` from console writes to avoid gateway crashes. (#925, fixes #878) — thanks @grp06.
|
||||||
- Sandbox: restore `docker.binds` config validation and preserve configured PATH for `docker exec`. (#873) — thanks @akonyer.
|
- Sandbox: restore `docker.binds` config validation and preserve configured PATH for `docker exec`. (#873) — thanks @akonyer.
|
||||||
- Google: downgrade unsigned thinking blocks before send to avoid missing signature errors.
|
- Google: downgrade unsigned thinking blocks before send to avoid missing signature errors.
|
||||||
|
- Agents: preserve Antigravity Claude signatures and skip Gemini downgrades. (#959) — thanks @rdev.
|
||||||
|
|
||||||
#### macOS / Apps
|
#### macOS / Apps
|
||||||
- macOS: ensure launchd log directory exists with a test-only override. (#909) — thanks @roshanasingh4.
|
- macOS: ensure launchd log directory exists with a test-only override. (#909) — thanks @roshanasingh4.
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ export function isGoogleModelApi(api?: string | null): boolean {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isAntigravityClaude(api?: string | null, modelId?: string): boolean {
|
||||||
|
if (api !== "google-antigravity") return false;
|
||||||
|
return modelId?.toLowerCase().includes("claude") ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export { sanitizeGoogleTurnOrdering };
|
export { sanitizeGoogleTurnOrdering };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ function isEmptyAssistantErrorMessage(
|
|||||||
export async function sanitizeSessionMessagesImages(
|
export async function sanitizeSessionMessagesImages(
|
||||||
messages: AgentMessage[],
|
messages: AgentMessage[],
|
||||||
label: string,
|
label: string,
|
||||||
options?: { sanitizeToolCallIds?: boolean; enforceToolCallLast?: boolean },
|
options?: { sanitizeToolCallIds?: boolean; enforceToolCallLast?: boolean; preserveSignatures?: boolean },
|
||||||
): Promise<AgentMessage[]> {
|
): Promise<AgentMessage[]> {
|
||||||
// We sanitize historical session messages because Anthropic can reject a request
|
// We sanitize historical session messages because Anthropic can reject a request
|
||||||
// if the transcript contains oversized base64 images (see MAX_IMAGE_DIMENSION_PX).
|
// if the transcript contains oversized base64 images (see MAX_IMAGE_DIMENSION_PX).
|
||||||
@@ -76,7 +76,10 @@ export async function sanitizeSessionMessagesImages(
|
|||||||
}
|
}
|
||||||
const content = assistantMsg.content;
|
const content = assistantMsg.content;
|
||||||
if (Array.isArray(content)) {
|
if (Array.isArray(content)) {
|
||||||
const strippedContent = stripThoughtSignatures(content);
|
const strippedContent = options?.preserveSignatures
|
||||||
|
? content // Keep signatures for Antigravity Claude
|
||||||
|
: stripThoughtSignatures(content); // Strip for Gemini
|
||||||
|
|
||||||
const filteredContent = strippedContent.filter((block) => {
|
const filteredContent = strippedContent.filter((block) => {
|
||||||
if (!block || typeof block !== "object") return true;
|
if (!block || typeof block !== "object") return true;
|
||||||
const rec = block as { type?: unknown; text?: unknown };
|
const rec = block as { type?: unknown; text?: unknown };
|
||||||
|
|||||||
@@ -59,6 +59,34 @@ describe("sanitizeSessionHistory (google thinking)", () => {
|
|||||||
expect(assistant.content?.[0]?.thinkingSignature).toBe("sig");
|
expect(assistant.content?.[0]?.thinkingSignature).toBe("sig");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("keeps unsigned thinking blocks for Antigravity Claude", async () => {
|
||||||
|
const sessionManager = SessionManager.inMemory();
|
||||||
|
const input = [
|
||||||
|
{
|
||||||
|
role: "user",
|
||||||
|
content: "hi",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
role: "assistant",
|
||||||
|
content: [{ type: "thinking", thinking: "reasoning" }],
|
||||||
|
},
|
||||||
|
] satisfies AgentMessage[];
|
||||||
|
|
||||||
|
const out = await sanitizeSessionHistory({
|
||||||
|
messages: input,
|
||||||
|
modelApi: "google-antigravity",
|
||||||
|
modelId: "anthropic/claude-3.5-sonnet",
|
||||||
|
sessionManager,
|
||||||
|
sessionId: "session:antigravity-claude",
|
||||||
|
});
|
||||||
|
|
||||||
|
const assistant = out.find((msg) => (msg as { role?: string }).role === "assistant") as {
|
||||||
|
content?: Array<{ type?: string; thinking?: string }>;
|
||||||
|
};
|
||||||
|
expect(assistant.content?.map((block) => block.type)).toEqual(["thinking"]);
|
||||||
|
expect(assistant.content?.[0]?.thinking).toBe("reasoning");
|
||||||
|
});
|
||||||
|
|
||||||
it("preserves order when downgrading mixed assistant content", async () => {
|
it("preserves order when downgrading mixed assistant content", async () => {
|
||||||
const sessionManager = SessionManager.inMemory();
|
const sessionManager = SessionManager.inMemory();
|
||||||
const input = [
|
const input = [
|
||||||
|
|||||||
@@ -302,6 +302,7 @@ export async function compactEmbeddedPiSession(params: {
|
|||||||
const prior = await sanitizeSessionHistory({
|
const prior = await sanitizeSessionHistory({
|
||||||
messages: session.messages,
|
messages: session.messages,
|
||||||
modelApi: model.api,
|
modelApi: model.api,
|
||||||
|
modelId,
|
||||||
sessionManager,
|
sessionManager,
|
||||||
sessionId: params.sessionId,
|
sessionId: params.sessionId,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
import { sanitizeToolUseResultPairing } from "../session-transcript-repair.js";
|
import { sanitizeToolUseResultPairing } from "../session-transcript-repair.js";
|
||||||
import { log } from "./logger.js";
|
import { log } from "./logger.js";
|
||||||
import { describeUnknownError } from "./utils.js";
|
import { describeUnknownError } from "./utils.js";
|
||||||
|
import { isAntigravityClaude } from "../pi-embedded-helpers/google.js";
|
||||||
|
|
||||||
const GOOGLE_TURN_ORDERING_CUSTOM_TYPE = "google-turn-ordering-bootstrap";
|
const GOOGLE_TURN_ORDERING_CUSTOM_TYPE = "google-turn-ordering-bootstrap";
|
||||||
const GOOGLE_SCHEMA_UNSUPPORTED_KEYWORDS = new Set([
|
const GOOGLE_SCHEMA_UNSUPPORTED_KEYWORDS = new Set([
|
||||||
@@ -152,19 +153,23 @@ export function applyGoogleTurnOrderingFix(params: {
|
|||||||
export async function sanitizeSessionHistory(params: {
|
export async function sanitizeSessionHistory(params: {
|
||||||
messages: AgentMessage[];
|
messages: AgentMessage[];
|
||||||
modelApi?: string | null;
|
modelApi?: string | null;
|
||||||
|
modelId?: string;
|
||||||
sessionManager: SessionManager;
|
sessionManager: SessionManager;
|
||||||
sessionId: string;
|
sessionId: string;
|
||||||
}): Promise<AgentMessage[]> {
|
}): Promise<AgentMessage[]> {
|
||||||
|
const isAntigravityClaudeModel = isAntigravityClaude(params.modelApi, params.modelId);
|
||||||
const sanitizedImages = await sanitizeSessionMessagesImages(params.messages, "session:history", {
|
const sanitizedImages = await sanitizeSessionMessagesImages(params.messages, "session:history", {
|
||||||
sanitizeToolCallIds: shouldSanitizeToolCallIds(params.modelApi),
|
sanitizeToolCallIds: shouldSanitizeToolCallIds(params.modelApi),
|
||||||
enforceToolCallLast: params.modelApi === "anthropic-messages",
|
enforceToolCallLast: params.modelApi === "anthropic-messages",
|
||||||
|
preserveSignatures: params.modelApi === "google-antigravity" && isAntigravityClaudeModel,
|
||||||
});
|
});
|
||||||
const repairedTools = sanitizeToolUseResultPairing(sanitizedImages);
|
const repairedTools = sanitizeToolUseResultPairing(sanitizedImages);
|
||||||
|
const shouldDowngradeGemini = isGoogleModelApi(params.modelApi) && !isAntigravityClaudeModel;
|
||||||
// Gemini rejects unsigned thinking blocks; downgrade them before send to avoid INVALID_ARGUMENT.
|
// Gemini rejects unsigned thinking blocks; downgrade them before send to avoid INVALID_ARGUMENT.
|
||||||
const downgradedThinking = isGoogleModelApi(params.modelApi)
|
const downgradedThinking = shouldDowngradeGemini
|
||||||
? downgradeGeminiThinkingBlocks(repairedTools)
|
? downgradeGeminiThinkingBlocks(repairedTools)
|
||||||
: repairedTools;
|
: repairedTools;
|
||||||
const downgraded = isGoogleModelApi(params.modelApi)
|
const downgraded = shouldDowngradeGemini
|
||||||
? downgradeGeminiHistory(downgradedThinking)
|
? downgradeGeminiHistory(downgradedThinking)
|
||||||
: downgradedThinking;
|
: downgradedThinking;
|
||||||
|
|
||||||
|
|||||||
@@ -303,6 +303,7 @@ export async function runEmbeddedAttempt(
|
|||||||
const prior = await sanitizeSessionHistory({
|
const prior = await sanitizeSessionHistory({
|
||||||
messages: activeSession.messages,
|
messages: activeSession.messages,
|
||||||
modelApi: params.model.api,
|
modelApi: params.model.api,
|
||||||
|
modelId: params.modelId,
|
||||||
sessionManager,
|
sessionManager,
|
||||||
sessionId: params.sessionId,
|
sessionId: params.sessionId,
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user