mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-12 07:20:45 +00:00
fix(models): synthesize antigravity Gemini 3.1 pro high/low models (#22899)
* Models: add antigravity Gemini 3.1 forward-compat * models: propagate availability to Gemini 3.1 dot IDs * test(models): format Gemini 3.1 forward-compat test * test(models): type Gemini 3.1 forward-compat fixtures * models: add changelog note for antigravity gemini 3.1 forward-compat --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
@@ -701,6 +701,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Agents/Context: apply configured model `contextWindow` overrides after provider discovery so `lookupContextTokens()` honors operator config values (including discovery-failure paths). (#17404) Thanks @michaelbship and @vignesh07.
|
||||
- Agents/Context: derive `lookupContextTokens()` from auth-available model metadata and keep the smallest discovered context window for duplicate model ids, preventing cross-provider cache collisions from overestimating session context limits. (#17586) Thanks @githabideri and @vignesh07.
|
||||
- Agents/OpenAI: force `store=true` for direct OpenAI Responses/Codex runs to preserve multi-turn server-side conversation state, while leaving proxy/non-OpenAI endpoints unchanged. (#16803) Thanks @mark9232 and @vignesh07.
|
||||
- Models/Antigravity: synthesize Gemini 3.1 Pro high/low model IDs (dash and dot forms) from Gemini 3 templates so `models list` and `/model` remain usable while upstream catalogs catch up. (#22492) Thanks @Phineas1500.
|
||||
- Memory/FTS: make `buildFtsQuery` Unicode-aware so non-ASCII queries (including CJK) produce keyword tokens instead of falling back to vector-only search. (#17672) Thanks @KinGP5471.
|
||||
- Auto-reply/Compaction: resolve `memory/YYYY-MM-DD.md` placeholders with timezone-aware runtime dates and append a `Current time:` line to memory-flush turns, preventing wrong-year memory filenames without making the system prompt time-variant. (#17603, #17633) Thanks @nicholaspapadam-wq and @vignesh07.
|
||||
- Auth/Cooldowns: auto-expire stale auth profile cooldowns when `cooldownUntil` or `disabledUntil` timestamps have passed, and reset `errorCount` so the next transient failure does not immediately escalate to a disproportionately long cooldown. Handles `cooldownUntil` and `disabledUntil` independently. (#3604) Thanks @nabbilkhan.
|
||||
|
||||
72
src/agents/model-forward-compat.antigravity-gemini31.test.ts
Normal file
72
src/agents/model-forward-compat.antigravity-gemini31.test.ts
Normal file
@@ -0,0 +1,72 @@
|
||||
import type { Api, Model } from "@mariozechner/pi-ai";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveForwardCompatModel } from "./model-forward-compat.js";
|
||||
import type { ModelRegistry } from "./pi-model-discovery.js";
|
||||
|
||||
function makeRegistry(): ModelRegistry {
|
||||
const templates = new Map<string, Model<Api>>();
|
||||
templates.set("google-antigravity/gemini-3-pro-high", {
|
||||
id: "gemini-3-pro-high",
|
||||
name: "Gemini 3 Pro High",
|
||||
provider: "google-antigravity",
|
||||
api: "google-antigravity",
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 200000,
|
||||
maxTokens: 64000,
|
||||
reasoning: true,
|
||||
} as Model<Api>);
|
||||
templates.set("google-antigravity/gemini-3-pro-low", {
|
||||
id: "gemini-3-pro-low",
|
||||
name: "Gemini 3 Pro Low",
|
||||
provider: "google-antigravity",
|
||||
api: "google-antigravity",
|
||||
input: ["text", "image"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 200000,
|
||||
maxTokens: 64000,
|
||||
reasoning: true,
|
||||
} as Model<Api>);
|
||||
|
||||
const registry = {
|
||||
find: (provider: string, modelId: string) => templates.get(`${provider}/${modelId}`) ?? null,
|
||||
} as unknown as ModelRegistry;
|
||||
return registry;
|
||||
}
|
||||
|
||||
describe("resolveForwardCompatModel (google-antigravity Gemini 3.1)", () => {
|
||||
it("resolves gemini-3-1-pro-high from gemini-3-pro-high template", () => {
|
||||
const model = resolveForwardCompatModel(
|
||||
"google-antigravity",
|
||||
"gemini-3-1-pro-high",
|
||||
makeRegistry(),
|
||||
);
|
||||
expect(model?.provider).toBe("google-antigravity");
|
||||
expect(model?.id).toBe("gemini-3-1-pro-high");
|
||||
});
|
||||
|
||||
it("resolves gemini-3-1-pro-low from gemini-3-pro-low template", () => {
|
||||
const model = resolveForwardCompatModel(
|
||||
"google-antigravity",
|
||||
"gemini-3-1-pro-low",
|
||||
makeRegistry(),
|
||||
);
|
||||
expect(model?.provider).toBe("google-antigravity");
|
||||
expect(model?.id).toBe("gemini-3-1-pro-low");
|
||||
});
|
||||
|
||||
it("supports dot-notation model ids", () => {
|
||||
const high = resolveForwardCompatModel(
|
||||
"google-antigravity",
|
||||
"gemini-3.1-pro-high",
|
||||
makeRegistry(),
|
||||
);
|
||||
const low = resolveForwardCompatModel(
|
||||
"google-antigravity",
|
||||
"gemini-3.1-pro-low",
|
||||
makeRegistry(),
|
||||
);
|
||||
expect(high?.id).toBe("gemini-3.1-pro-high");
|
||||
expect(low?.id).toBe("gemini-3.1-pro-low");
|
||||
});
|
||||
});
|
||||
@@ -26,6 +26,12 @@ const ANTIGRAVITY_OPUS_THINKING_TEMPLATE_MODEL_IDS = [
|
||||
"claude-opus-4-5-thinking",
|
||||
"claude-opus-4.5-thinking",
|
||||
] as const;
|
||||
const ANTIGRAVITY_GEMINI_31_PRO_HIGH_MODEL_ID = "gemini-3-1-pro-high";
|
||||
const ANTIGRAVITY_GEMINI_31_PRO_DOT_HIGH_MODEL_ID = "gemini-3.1-pro-high";
|
||||
const ANTIGRAVITY_GEMINI_31_PRO_LOW_MODEL_ID = "gemini-3-1-pro-low";
|
||||
const ANTIGRAVITY_GEMINI_31_PRO_DOT_LOW_MODEL_ID = "gemini-3.1-pro-low";
|
||||
const ANTIGRAVITY_GEMINI_31_PRO_HIGH_TEMPLATE_MODEL_IDS = ["gemini-3-pro-high"] as const;
|
||||
const ANTIGRAVITY_GEMINI_31_PRO_LOW_TEMPLATE_MODEL_IDS = ["gemini-3-pro-low"] as const;
|
||||
|
||||
export const ANTIGRAVITY_OPUS_46_FORWARD_COMPAT_CANDIDATES = [
|
||||
{
|
||||
@@ -34,10 +40,25 @@ export const ANTIGRAVITY_OPUS_46_FORWARD_COMPAT_CANDIDATES = [
|
||||
"google-antigravity/claude-opus-4-5-thinking",
|
||||
"google-antigravity/claude-opus-4.5-thinking",
|
||||
],
|
||||
availabilityAliasIds: [] as const,
|
||||
},
|
||||
{
|
||||
id: ANTIGRAVITY_OPUS_46_MODEL_ID,
|
||||
templatePrefixes: ["google-antigravity/claude-opus-4-5", "google-antigravity/claude-opus-4.5"],
|
||||
availabilityAliasIds: [] as const,
|
||||
},
|
||||
] as const;
|
||||
|
||||
export const ANTIGRAVITY_GEMINI_31_FORWARD_COMPAT_CANDIDATES = [
|
||||
{
|
||||
id: ANTIGRAVITY_GEMINI_31_PRO_HIGH_MODEL_ID,
|
||||
templatePrefixes: ["google-antigravity/gemini-3-pro-high"],
|
||||
availabilityAliasIds: [ANTIGRAVITY_GEMINI_31_PRO_DOT_HIGH_MODEL_ID],
|
||||
},
|
||||
{
|
||||
id: ANTIGRAVITY_GEMINI_31_PRO_LOW_MODEL_ID,
|
||||
templatePrefixes: ["google-antigravity/gemini-3-pro-low"],
|
||||
availabilityAliasIds: [ANTIGRAVITY_GEMINI_31_PRO_DOT_LOW_MODEL_ID],
|
||||
},
|
||||
] as const;
|
||||
|
||||
@@ -278,6 +299,40 @@ function resolveAntigravityOpus46ForwardCompatModel(
|
||||
});
|
||||
}
|
||||
|
||||
function resolveAntigravityGemini31ForwardCompatModel(
|
||||
provider: string,
|
||||
modelId: string,
|
||||
modelRegistry: ModelRegistry,
|
||||
): Model<Api> | undefined {
|
||||
const normalizedProvider = normalizeProviderId(provider);
|
||||
if (normalizedProvider !== "google-antigravity") {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const trimmedModelId = modelId.trim();
|
||||
const lower = trimmedModelId.toLowerCase();
|
||||
const isGemini31High =
|
||||
lower === ANTIGRAVITY_GEMINI_31_PRO_HIGH_MODEL_ID ||
|
||||
lower === ANTIGRAVITY_GEMINI_31_PRO_DOT_HIGH_MODEL_ID;
|
||||
const isGemini31Low =
|
||||
lower === ANTIGRAVITY_GEMINI_31_PRO_LOW_MODEL_ID ||
|
||||
lower === ANTIGRAVITY_GEMINI_31_PRO_DOT_LOW_MODEL_ID;
|
||||
if (!isGemini31High && !isGemini31Low) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const templateIds = isGemini31High
|
||||
? [...ANTIGRAVITY_GEMINI_31_PRO_HIGH_TEMPLATE_MODEL_IDS]
|
||||
: [...ANTIGRAVITY_GEMINI_31_PRO_LOW_TEMPLATE_MODEL_IDS];
|
||||
|
||||
return cloneFirstTemplateModel({
|
||||
normalizedProvider,
|
||||
trimmedModelId,
|
||||
templateIds,
|
||||
modelRegistry,
|
||||
});
|
||||
}
|
||||
|
||||
export function resolveForwardCompatModel(
|
||||
provider: string,
|
||||
modelId: string,
|
||||
@@ -288,6 +343,7 @@ export function resolveForwardCompatModel(
|
||||
resolveAnthropicOpus46ForwardCompatModel(provider, modelId, modelRegistry) ??
|
||||
resolveAnthropicSonnet46ForwardCompatModel(provider, modelId, modelRegistry) ??
|
||||
resolveZaiGlm5ForwardCompatModel(provider, modelId, modelRegistry) ??
|
||||
resolveAntigravityOpus46ForwardCompatModel(provider, modelId, modelRegistry)
|
||||
resolveAntigravityOpus46ForwardCompatModel(provider, modelId, modelRegistry) ??
|
||||
resolveAntigravityGemini31ForwardCompatModel(provider, modelId, modelRegistry)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -389,6 +389,99 @@ describe("models list/status", () => {
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "high",
|
||||
configuredModelId: "gemini-3-1-pro-high",
|
||||
templateId: "gemini-3-pro-high",
|
||||
templateName: "Gemini 3 Pro High",
|
||||
expectedKey: "google-antigravity/gemini-3-1-pro-high",
|
||||
},
|
||||
{
|
||||
name: "low",
|
||||
configuredModelId: "gemini-3-1-pro-low",
|
||||
templateId: "gemini-3-pro-low",
|
||||
templateName: "Gemini 3 Pro Low",
|
||||
expectedKey: "google-antigravity/gemini-3-1-pro-low",
|
||||
},
|
||||
] as const)(
|
||||
"models list resolves antigravity gemini 3.1 $name from gemini 3 template",
|
||||
async ({ configuredModelId, templateId, templateName, expectedKey }) => {
|
||||
const payload = await runGoogleAntigravityListCase({
|
||||
configuredModelId,
|
||||
templateId,
|
||||
templateName,
|
||||
});
|
||||
expectAntigravityModel(payload, {
|
||||
key: expectedKey,
|
||||
available: false,
|
||||
includesTags: true,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "high",
|
||||
configuredModelId: "gemini-3-1-pro-high",
|
||||
templateId: "gemini-3-pro-high",
|
||||
templateName: "Gemini 3 Pro High",
|
||||
expectedKey: "google-antigravity/gemini-3-1-pro-high",
|
||||
},
|
||||
{
|
||||
name: "low",
|
||||
configuredModelId: "gemini-3-1-pro-low",
|
||||
templateId: "gemini-3-pro-low",
|
||||
templateName: "Gemini 3 Pro Low",
|
||||
expectedKey: "google-antigravity/gemini-3-1-pro-low",
|
||||
},
|
||||
] as const)(
|
||||
"models list marks synthesized antigravity gemini 3.1 $name as available when template is available",
|
||||
async ({ configuredModelId, templateId, templateName, expectedKey }) => {
|
||||
const payload = await runGoogleAntigravityListCase({
|
||||
configuredModelId,
|
||||
templateId,
|
||||
templateName,
|
||||
available: true,
|
||||
});
|
||||
expectAntigravityModel(payload, {
|
||||
key: expectedKey,
|
||||
available: true,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
{
|
||||
name: "high",
|
||||
configuredModelId: "gemini-3.1-pro-high",
|
||||
templateId: "gemini-3-pro-high",
|
||||
templateName: "Gemini 3 Pro High",
|
||||
expectedKey: "google-antigravity/gemini-3.1-pro-high",
|
||||
},
|
||||
{
|
||||
name: "low",
|
||||
configuredModelId: "gemini-3.1-pro-low",
|
||||
templateId: "gemini-3-pro-low",
|
||||
templateName: "Gemini 3 Pro Low",
|
||||
expectedKey: "google-antigravity/gemini-3.1-pro-low",
|
||||
},
|
||||
] as const)(
|
||||
"models list marks dot-notation antigravity gemini 3.1 $name as available when template is available",
|
||||
async ({ configuredModelId, templateId, templateName, expectedKey }) => {
|
||||
const payload = await runGoogleAntigravityListCase({
|
||||
configuredModelId,
|
||||
templateId,
|
||||
templateName,
|
||||
available: true,
|
||||
});
|
||||
expectAntigravityModel(payload, {
|
||||
key: expectedKey,
|
||||
available: true,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it("models list prefers registry availability over provider auth heuristics", async () => {
|
||||
const payload = await runGoogleAntigravityListCase({
|
||||
configuredModelId: "claude-opus-4-6-thinking",
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
resolveEnvApiKey,
|
||||
} from "../../agents/model-auth.js";
|
||||
import {
|
||||
ANTIGRAVITY_GEMINI_31_FORWARD_COMPAT_CANDIDATES,
|
||||
ANTIGRAVITY_OPUS_46_FORWARD_COMPAT_CANDIDATES,
|
||||
resolveForwardCompatModel,
|
||||
} from "../../agents/model-forward-compat.js";
|
||||
@@ -117,6 +118,9 @@ export async function loadModelRegistry(cfg: OpenClawConfig) {
|
||||
for (const synthesized of synthesizedForwardCompat) {
|
||||
if (hasAvailableTemplate(availableKeys, synthesized.templatePrefixes)) {
|
||||
availableKeys.add(synthesized.key);
|
||||
for (const aliasKey of synthesized.availabilityAliasKeys) {
|
||||
availableKeys.add(aliasKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -137,6 +141,7 @@ export async function loadModelRegistry(cfg: OpenClawConfig) {
|
||||
type SynthesizedForwardCompat = {
|
||||
key: string;
|
||||
templatePrefixes: readonly string[];
|
||||
availabilityAliasKeys: readonly string[];
|
||||
};
|
||||
|
||||
function appendAntigravityForwardCompatModels(
|
||||
@@ -145,8 +150,12 @@ function appendAntigravityForwardCompatModels(
|
||||
): { models: Model<Api>[]; synthesizedForwardCompat: SynthesizedForwardCompat[] } {
|
||||
const nextModels = [...models];
|
||||
const synthesizedForwardCompat: SynthesizedForwardCompat[] = [];
|
||||
const candidates = [
|
||||
...ANTIGRAVITY_OPUS_46_FORWARD_COMPAT_CANDIDATES,
|
||||
...ANTIGRAVITY_GEMINI_31_FORWARD_COMPAT_CANDIDATES,
|
||||
];
|
||||
|
||||
for (const candidate of ANTIGRAVITY_OPUS_46_FORWARD_COMPAT_CANDIDATES) {
|
||||
for (const candidate of candidates) {
|
||||
const key = modelKey("google-antigravity", candidate.id);
|
||||
const hasForwardCompat = nextModels.some((model) => modelKey(model.provider, model.id) === key);
|
||||
if (hasForwardCompat) {
|
||||
@@ -162,6 +171,9 @@ function appendAntigravityForwardCompatModels(
|
||||
synthesizedForwardCompat.push({
|
||||
key,
|
||||
templatePrefixes: candidate.templatePrefixes,
|
||||
availabilityAliasKeys: candidate.availabilityAliasIds.map((id) =>
|
||||
modelKey("google-antigravity", id),
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user