From 590429102abf4b6c6b24c14e6ed94df80867e654 Mon Sep 17 00:00:00 2001 From: mweinbach Date: Mon, 26 Oct 2026 11:24:38 -0400 Subject: [PATCH 1/4] chore(server): update Antigravity ACP to 1.4.3 --- .../server/src/provider/antigravityRelease.ts | 62 +++++++++---------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/apps/server/src/provider/antigravityRelease.ts b/apps/server/src/provider/antigravityRelease.ts index f00185865b05a..175eeda55cfb3 100644 --- a/apps/server/src/provider/antigravityRelease.ts +++ b/apps/server/src/provider/antigravityRelease.ts @@ -1,4 +1,4 @@ -const ANTIGRAVITY_RELEASE_VERSION = "1.3.0"; +const ANTIGRAVITY_RELEASE_VERSION = "1.4.3"; export interface AntigravityReleaseAsset { readonly version: string; @@ -20,66 +20,66 @@ const releaseAssets = new Map([ "darwin-arm64", { version: ANTIGRAVITY_RELEASE_VERSION, - url: "https://dl.google.com/agy-extensions/releases/macos/agy-acp-server-1.3.0-darwin-arm64.zip", - sha256: "7cd97045f7b4fe81175a107cdf16f9c51484e3c78a5162cae415338bb6aa5b88", - archiveBytes: 111_456_962, - executable: { name: "agy_acp_server.par", bytes: 278_535_456 }, - harness: { name: "localharness_external", bytes: 118_611_392 }, + url: "https://dl.google.com/agy-extensions/releases/macos/agy-acp-server-1.4.3-darwin-arm64.zip", + sha256: "c57db0a9b8b712daa9c3c17cdb990a61842ea569f279e8bd79d7aa85a303b20b", + archiveBytes: 114_147_623, + executable: { name: "agy_acp_server.par", bytes: 282_446_160 }, + harness: { name: "localharness_external", bytes: 122_957_936 }, }, ], [ "darwin-x64", { version: ANTIGRAVITY_RELEASE_VERSION, - url: "https://dl.google.com/agy-extensions/releases/macos/agy-acp-server-1.3.0-darwin-x86_64.zip", - sha256: "bb23956b89984bf5d354af2c3725e6c57f0cc1b7228e77a0e91c9c2bc1d47646", - archiveBytes: 117_245_544, - executable: { name: "agy_acp_server.par", bytes: 282_840_688 }, - harness: { name: "localharness_external", bytes: 124_175_392 }, + url: "https://dl.google.com/agy-extensions/releases/macos/agy-acp-server-1.4.3-darwin-x86_64.zip", + sha256: "9392dbbdad7f0663dbfb5a0bf641297b0cf80d2ee9cd2d49a616bbbc7378731d", + archiveBytes: 119_801_100, + executable: { name: "agy_acp_server.par", bytes: 286_653_712 }, + harness: { name: "localharness_external", bytes: 127_612_208 }, }, ], [ "linux-x64", { version: ANTIGRAVITY_RELEASE_VERSION, - url: "https://dl.google.com/agy-extensions/releases/linux/agy-acp-server-1.3.0-linux-x86_64.zip", - sha256: "9fb60956af0a9d76220a4db91ca9ac88e2a2372ad68f985ab5fceace6b825b96", - archiveBytes: 333_727_150, - executable: { name: "agy_acp_server.par", bytes: 926_533_965 }, - harness: { name: "localharness_external", bytes: 130_388_040 }, + url: "https://dl.google.com/agy-extensions/releases/linux/agy-acp-server-1.4.3-linux-x86_64.zip", + sha256: "0634ce5306ba92c932945455e7a83fda78e2d99c33fa8aa6ee0566206a382714", + archiveBytes: 336_846_435, + executable: { name: "agy_acp_server.par", bytes: 927_707_135 }, + harness: { name: "localharness_external", bytes: 133_926_136 }, }, ], [ "linux-arm64", { version: ANTIGRAVITY_RELEASE_VERSION, - url: "https://dl.google.com/agy-extensions/releases/linux/agy-acp-server-1.3.0-linux-arm64.zip", - sha256: "500b0bc0fb858e88f4df404d4cedf80bf9298c178291e39e383d6c50b111cbdf", - archiveBytes: 321_690_363, - executable: { name: "agy_acp_server.par", bytes: 930_848_992 }, - harness: { name: "localharness_external", bytes: 123_224_968 }, + url: "https://dl.google.com/agy-extensions/releases/linux/agy-acp-server-1.4.3-linux-arm64.zip", + sha256: "05c153443b0b1175151c760eeddea538950bc9843e317d54786a1f03670182bc", + archiveBytes: 322_887_047, + executable: { name: "agy_acp_server.par", bytes: 932_662_106 }, + harness: { name: "localharness_external", bytes: 127_512_832 }, }, ], [ "win32-x64", { version: ANTIGRAVITY_RELEASE_VERSION, - url: "https://dl.google.com/agy-extensions/releases/windows/agy-acp-server-1.3.0-windows-x86_64.zip", - sha256: "65215e0688681fa3116e048a9eab27ef53af1bbd6f3da3f1c52bd4911d8b17f9", - archiveBytes: 124_509_787, - executable: { name: "agy_acp_server.exe", bytes: 81_437_336 }, - harness: { name: "localharness_external.exe", bytes: 145_548_952 }, + url: "https://dl.google.com/agy-extensions/releases/windows/agy-acp-server-1.4.3-windows-x86_64.zip", + sha256: "54c2e16378d9a4952e1da70e355f3c33c4f284308d6de48ab3e6e34a127bd325", + archiveBytes: 131_267_135, + executable: { name: "agy_acp_server.exe", bytes: 87_022_872 }, + harness: { name: "localharness_external.exe", bytes: 147_843_736 }, }, ], [ "win32-arm64", { version: ANTIGRAVITY_RELEASE_VERSION, - url: "https://dl.google.com/agy-extensions/releases/windows/agy-acp-server-1.3.0-windows-arm64.zip", - sha256: "4a0f469720e9beb9438a979f543fdbfad5022ebe0992c052c590bd78b3144ca3", - archiveBytes: 124_654_803, - executable: { name: "agy_acp_server.exe", bytes: 85_893_472 }, - harness: { name: "localharness_external.exe", bytes: 135_640_216 }, + url: "https://dl.google.com/agy-extensions/releases/windows/agy-acp-server-1.4.3-windows-arm64.zip", + sha256: "fcd46431ad33d3b510ce0b98fe7b43d095bd8b3f1c363ee2d57faa7ee981c7bb", + archiveBytes: 134_301_870, + executable: { name: "agy_acp_server.exe", bytes: 94_238_816 }, + harness: { name: "localharness_external.exe", bytes: 139_322_008 }, }, ], ]); From 9e57f4f42f0bb8dc287d35a9302fed9b69c3b89e Mon Sep 17 00:00:00 2001 From: mweinbach Date: Mon, 26 Oct 2026 11:39:05 -0400 Subject: [PATCH 2/4] feat(server): Antigravity can report a custom ACP client name and keeps ACP 1.4.3 model choices Co-authored-by: Cursor --- .../Adapters/AntigravityAdapterV2.ts | 2 + .../src/provider/AntigravityProvider.test.ts | 30 +++++++++ .../src/provider/AntigravityProvider.ts | 17 +++-- .../Drivers/AntigravityDriver.test.ts | 14 ++++ .../src/provider/Drivers/AntigravityDriver.ts | 3 + .../acp/AntigravityAcpSupport.test.ts | 35 +++++++++- .../src/provider/acp/AntigravityAcpSupport.ts | 64 ++++++++++++------- .../provider/acp/antigravity143.fixture.ts | 45 +++++++++++++ .../AntigravityTextGeneration.test.ts | 1 + .../AntigravityTextGeneration.ts | 2 + .../src/components/settings/settingsSearch.ts | 2 +- docs/user/providers-antigravity.md | 6 ++ packages/contracts/src/settings.ts | 13 +++- 13 files changed, 203 insertions(+), 31 deletions(-) create mode 100644 apps/server/src/provider/acp/antigravity143.fixture.ts diff --git a/apps/server/src/orchestration-v2/Adapters/AntigravityAdapterV2.ts b/apps/server/src/orchestration-v2/Adapters/AntigravityAdapterV2.ts index a37781debe460..2ddb678926d44 100644 --- a/apps/server/src/orchestration-v2/Adapters/AntigravityAdapterV2.ts +++ b/apps/server/src/orchestration-v2/Adapters/AntigravityAdapterV2.ts @@ -172,11 +172,13 @@ export function makeAntigravityAcpAdapterFlavor( ...(options.onSessionEvent === undefined ? {} : { onSessionEvent: options.onSessionEvent }), applyModelSelection: Effect.fn("AntigravityAdapterV2.applyModelSelection")(function* ({ runtime, + startResult, modelSelection, }) { const defaultModel = yield* options.defaultModel; return yield* applyAntigravityAcpModelSelection({ runtime, + models: startResult.sessionSetupResult.models, model: modelSelection.model === ANTIGRAVITY_DEFAULT_MODEL ? undefined : modelSelection.model, defaultModel, diff --git a/apps/server/src/provider/AntigravityProvider.test.ts b/apps/server/src/provider/AntigravityProvider.test.ts index ade033551f655..16240ce3037fe 100644 --- a/apps/server/src/provider/AntigravityProvider.test.ts +++ b/apps/server/src/provider/AntigravityProvider.test.ts @@ -28,6 +28,7 @@ import { buildAntigravityModelsFromSession, makeAntigravityProvider, } from "./AntigravityProvider.ts"; +import { antigravity143Session } from "./acp/antigravity143.fixture.ts"; const decodeSettings = Schema.decodeSync(AntigravitySettings); const instanceId = ProviderInstanceId.make("antigravity-test"); @@ -358,6 +359,35 @@ it.layer(layerTest)("Antigravity provider snapshots", (it) => { ), ); + it.effect("lists ACP 1.4 concrete models through grouped thinking-level updates", () => + Effect.scoped( + Effect.gen(function* () { + const harness = yield* makeHarness(); + yield* harness.initialize; + yield* harness.provider.onSessionStarted({ + ...started, + sessionSetupResult: antigravity143Session, + }); + const snapshot = yield* harness.provider.snapshot.getSnapshot; + expect(snapshot.models.map((model) => model.slug)).toEqual( + antigravity143Session.models.availableModels.map((model) => model.modelId), + ); + expect(snapshot.models.find((model) => model.isDefault)?.slug).toBe( + "gemini-3.8-flash-high", + ); + + yield* harness.provider.onConfigOptionsUpdated( + antigravity143Session.configOptions.map((option) => + option.id === "model" + ? { ...option, currentValue: "claude-sonnet-5-5" } + : { ...option, currentValue: "low" }, + ), + ); + expect((yield* harness.provider.snapshot.getSnapshot).models).toEqual(snapshot.models); + }), + ), + ); + it.effect("does not guess a version before a custom launcher's first handshake", () => Effect.scoped( Effect.gen(function* () { diff --git a/apps/server/src/provider/AntigravityProvider.ts b/apps/server/src/provider/AntigravityProvider.ts index c6809c3577132..8f2cc9cc0cb2d 100644 --- a/apps/server/src/provider/AntigravityProvider.ts +++ b/apps/server/src/provider/AntigravityProvider.ts @@ -31,6 +31,7 @@ import { type ServerProviderDraft, } from "@t3tools/provider-core/server/snapshotProbe"; import { resolveUsageLimitsAfterProbe } from "@t3tools/provider-core/server/usageLimits"; +import { antigravityGroupedModels } from "./acp/AntigravityAcpSupport.ts"; const EMPTY_MODEL_CAPABILITIES = createModelCapabilities({ optionDescriptors: [] }); const MAX_WORKSPACE_SNAPSHOTS = 32; @@ -47,9 +48,9 @@ type SessionSetupResult = Pick< export function buildAntigravityModelsFromSession( setup: SessionSetupResult, ): ReadonlyArray { - const config = setup.configOptions?.find( - (option) => option.id === "model" || option.category === "model", - ); + const config = antigravityGroupedModels(setup) + ? undefined + : setup.configOptions?.find((option) => option.id === "model" || option.category === "model"); const currentValue = config?.type === "select" ? config.currentValue : setup.models?.currentModelId; const entries = @@ -115,6 +116,8 @@ function isMissingInstallation(error: EffectAcpErrors.AcpError | ProviderSetupEr interface AntigravityProviderState { readonly draft: ServerProviderDraft; readonly authRevision: number; + /** Config updates omit `models`, so keep the last session's concrete list. */ + readonly sessionModels: EffectAcpSchema.SessionModelState | null; } interface AntigravityProviderOptions { @@ -159,6 +162,7 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func const metadata = yield* SubscriptionRef.make({ draft: initialDraft, authRevision: 0, + sessionModels: null, }); // Preserve disk-discovered skills when callbacks replace workspace commands; the registry will not rescan them. const discoveredSkills = new Map(); @@ -286,6 +290,7 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func const workspace = cwd ? workspaces.find((entry) => entry.cwd === cwd) : undefined; return { authRevision: state.authRevision + 1, + sessionModels: started.sessionSetupResult.models ?? null, draft: { ...draft, installed: true, @@ -324,9 +329,12 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func const onConfigOptionsUpdated = Effect.fn("AntigravityProvider.onConfigOptionsUpdated")(function* ( configOptions: ReadonlyArray, ) { - const models = buildAntigravityModelsFromSession({ configOptions }); yield* SubscriptionRef.update(metadata, (state) => { if (state.draft.auth.status !== "authenticated") return state; + const models = buildAntigravityModelsFromSession({ + configOptions, + models: antigravityGroupedModels({ configOptions, models: state.sessionModels }) ?? null, + }); return { ...state, draft: { ...state.draft, models } }; }); }); @@ -375,6 +383,7 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func (state) => ({ authRevision: state.authRevision + 1, + sessionModels: null, draft: { ...state.draft, auth: { status: "unauthenticated" }, diff --git a/apps/server/src/provider/Drivers/AntigravityDriver.test.ts b/apps/server/src/provider/Drivers/AntigravityDriver.test.ts index 74f4daa1323af..182643ee88f58 100644 --- a/apps/server/src/provider/Drivers/AntigravityDriver.test.ts +++ b/apps/server/src/provider/Drivers/AntigravityDriver.test.ts @@ -333,6 +333,20 @@ it.layer(layerTest)("AntigravityDriver", (it) => { }).pipe(Effect.scoped), ); + it.effect.skipIf(windowsHost)("reports the configured ACP client name to the agent", () => + Effect.gen(function* () { + const h = yield* makeHarness({ config: { acpClientName: "custom-client" } }); + yield* h.refresh(); + const requests = yield* h.readRequests; + expect( + requests + .filter((request) => request.method === "initialize") + .map((request) => request.params?.clientInfo), + ).toEqual([{ name: "custom-client", version: "0.0.0" }]); + yield* h.assertClosed; + }).pipe(Effect.scoped), + ); + it.effect.skipIf(windowsHost)( "closes refresh processes and clears account metadata when Google sign-in is required", () => diff --git a/apps/server/src/provider/Drivers/AntigravityDriver.ts b/apps/server/src/provider/Drivers/AntigravityDriver.ts index fe974dee763ff..29ba0689a896c 100644 --- a/apps/server/src/provider/Drivers/AntigravityDriver.ts +++ b/apps/server/src/provider/Drivers/AntigravityDriver.ts @@ -241,6 +241,9 @@ export const AntigravityDriver: ProviderDriver< ); const runtime = yield* makeAntigravityAcpRuntime({ ...input, + ...(settings.acpClientName + ? { clientInfo: { ...input.clientInfo, name: settings.acpClientName } } + : {}), authMethod: auth.authMethod, childProcessSpawner: spawner, spawn: buildAntigravityAcpSpawnInput({ diff --git a/apps/server/src/provider/acp/AntigravityAcpSupport.test.ts b/apps/server/src/provider/acp/AntigravityAcpSupport.test.ts index bd48ee767ee46..e1273dcc55866 100644 --- a/apps/server/src/provider/acp/AntigravityAcpSupport.test.ts +++ b/apps/server/src/provider/acp/AntigravityAcpSupport.test.ts @@ -17,6 +17,7 @@ import { applyAntigravityAcpModelSelection, buildAntigravityPrompt, } from "./AntigravityAcpSupport.ts"; +import { antigravity143Session } from "./antigravity143.fixture.ts"; const modelConfig = { id: "model", @@ -34,13 +35,20 @@ function makeModelRuntime( failure?: EffectAcpErrors.AcpError, ) { const selections: string[] = []; + const sessionModelSelections: string[] = []; const setModel = Effect.fn("AntigravityAcpSupportTest.setModel")(function* (model: string) { if (failure) return yield* failure; selections.push(model); }); + const setSessionModel = (model: string) => + Effect.sync(() => { + sessionModelSelections.push(model); + return {}; + }); return { - runtime: { getConfigOptions: Effect.succeed(configOptions), setModel }, + runtime: { getConfigOptions: Effect.succeed(configOptions), setModel, setSessionModel }, selections, + sessionModelSelections, }; } @@ -137,6 +145,31 @@ describe("applyAntigravityAcpModelSelection", () => { expect(selections).toEqual(["gemini-saved"]); }), ); + + it.effect("selects concrete models when ACP 1.4 groups thinking levels by family", () => + Effect.gen(function* () { + const { runtime, selections, sessionModelSelections } = makeModelRuntime( + antigravity143Session.configOptions, + ); + const select = (model: string) => + applyAntigravityAcpModelSelection({ + runtime, + models: antigravity143Session.models, + model, + defaultModel: "gemini-3.8-flash-high", + mapError: (cause) => cause, + }); + + expect(yield* select("claude-sonnet-5-5-low")).toBe("claude-sonnet-5-5-low"); + expect(yield* select(ANTIGRAVITY_DEFAULT_MODEL)).toBe("gemini-3.8-flash-high"); + expect(sessionModelSelections).toEqual(["claude-sonnet-5-5-low", "gemini-3.8-flash-high"]); + expect(selections).toEqual([]); + + const error = yield* select("claude-opus-5-5-low").pipe(Effect.flip); + expect(error).toMatchObject({ _tag: "AcpRequestError", code: -32602 }); + expect(sessionModelSelections).toHaveLength(2); + }), + ); }); const imageAttachment = { diff --git a/apps/server/src/provider/acp/AntigravityAcpSupport.ts b/apps/server/src/provider/acp/AntigravityAcpSupport.ts index 8ddbf575c8f1e..f89130878d00c 100644 --- a/apps/server/src/provider/acp/AntigravityAcpSupport.ts +++ b/apps/server/src/provider/acp/AntigravityAcpSupport.ts @@ -100,18 +100,21 @@ function antigravityModelOptions( return model.options.flatMap((entry) => ("value" in entry ? [entry] : entry.options)); } -function resolveAntigravityModel(input: { - readonly configOptions: ReadonlyArray; - readonly model: string | null | undefined; - readonly defaultModel?: string | undefined; -}): string | undefined { - const modelConfig = input.configOptions.find((option) => option.id === "model"); - const current = modelConfig?.type === "select" ? modelConfig.currentValue : undefined; - if (input.model && input.model !== ANTIGRAVITY_DEFAULT_MODEL) return input.model; - const options = antigravityModelOptions(input.configOptions); - return input.defaultModel && options.some((option) => option.value === input.defaultModel) - ? input.defaultModel - : current; +/** + * ACP 1.4 folds thinking-level variants into one `model` value per family. Only + * the session's `models` state lists the concrete IDs the agent runs. + */ +export function antigravityGroupedModels(setup: { + readonly configOptions?: ReadonlyArray | null | undefined; + readonly models?: EffectAcpSchema.SessionModelState | null | undefined; +}): EffectAcpSchema.SessionModelState | undefined { + if (!setup.models) return undefined; + const concrete = new Set(setup.models.availableModels.map((model) => model.modelId)); + return antigravityModelOptions(setup.configOptions ?? []).some( + (option) => !concrete.has(option.value), + ) + ? setup.models + : undefined; } /** Never replace a saved selection with the default returned by a cold resume. */ @@ -119,33 +122,46 @@ export const applyAntigravityAcpModelSelection = Effect.fn("applyAntigravityAcpM function* (input: { readonly runtime: Pick< AcpSessionRuntime.AcpSessionRuntime["Service"], - "getConfigOptions" | "setModel" + "getConfigOptions" | "setModel" | "setSessionModel" >; + readonly models?: EffectAcpSchema.SessionModelState | null | undefined; readonly model: string | null | undefined; readonly defaultModel?: string | undefined; readonly mapError: (cause: EffectAcpErrors.AcpError) => E; }): Effect.fn.Return { const configOptions = yield* input.runtime.getConfigOptions; + const grouped = antigravityGroupedModels({ configOptions, models: input.models }); const modelConfig = configOptions.find((option) => option.id === "model"); - const current = modelConfig?.type === "select" ? modelConfig.currentValue : undefined; - const resolved = resolveAntigravityModel({ - configOptions, - model: input.model, - defaultModel: input.defaultModel, - }); - const explicit = Boolean(input.model) && input.model !== ANTIGRAVITY_DEFAULT_MODEL; - if (resolved === undefined || (!explicit && resolved === current)) return current; - const options = antigravityModelOptions(configOptions); + const current = grouped + ? grouped.currentModelId + : modelConfig?.type === "select" + ? modelConfig.currentValue + : undefined; + const options = grouped + ? grouped.availableModels.map((model) => ({ value: model.modelId })) + : antigravityModelOptions(configOptions); + const explicit = input.model && input.model !== ANTIGRAVITY_DEFAULT_MODEL ? input.model : null; + const resolved = + explicit ?? + (input.defaultModel && options.some((option) => option.value === input.defaultModel) + ? input.defaultModel + : current); + // Setup-time model state is stale once a thinking level changes, so grouped + // selections are always reapplied. + if (resolved === undefined || (!grouped && !explicit && resolved === current)) return current; if (!options.some((option) => option.value === resolved)) { return yield* Effect.fail( input.mapError( EffectAcpErrors.AcpRequestError.invalidParams( - `Antigravity model '${resolved}' is unavailable for this Google account. Select an available model.`, + `Antigravity model '${resolved}' is unavailable for this Google account or ACP client name. Select an available model.`, ), ), ); } - yield* input.runtime.setModel(resolved).pipe(Effect.mapError(input.mapError)); + // The runtime validates `model` config values, which only list families here. + yield* ( + grouped ? input.runtime.setSessionModel(resolved) : input.runtime.setModel(resolved) + ).pipe(Effect.mapError(input.mapError)); return resolved; }, ); diff --git a/apps/server/src/provider/acp/antigravity143.fixture.ts b/apps/server/src/provider/acp/antigravity143.fixture.ts new file mode 100644 index 0000000000000..91ead8ff1ad55 --- /dev/null +++ b/apps/server/src/provider/acp/antigravity143.fixture.ts @@ -0,0 +1,45 @@ +import type * as EffectAcpSchema from "effect-acp/compat"; + +// Trimmed from ACP 1.4.3 session/new for a personal Google account on the +// third-party model allowlist. +export const antigravity143Session = { + sessionId: "8e3c4b2a-7f61-4d0e-9a55-2b1f0c6d9e47", + models: { + currentModelId: "gemini-3.8-flash-high", + availableModels: [ + { modelId: "gemini-3.8-flash-high", name: "Gemini 3.8 Flash (High)" }, + { modelId: "gemini-3.8-flash-medium", name: "Gemini 3.8 Flash (Medium)" }, + { modelId: "gemini-3.8-flash-low", name: "Gemini 3.8 Flash (Low)" }, + { modelId: "claude-sonnet-5-5-low", name: "Claude Sonnet 5.5 (Low)" }, + { modelId: "claude-sonnet-5-5-medium", name: "Claude Sonnet 5.5 (Medium)" }, + { modelId: "claude-sonnet-5-5-high", name: "Claude Sonnet 5.5 (High)" }, + { modelId: "gpt-oss-120b-medium", name: "GPT-OSS 120B (Medium)" }, + ], + }, + configOptions: [ + { + id: "model", + name: "Model", + category: "model", + type: "select", + currentValue: "gemini-3.8-flash", + options: [ + { value: "gemini-3.8-flash", name: "Gemini 3.8 Flash" }, + { value: "claude-sonnet-5-5", name: "Claude Sonnet 5.5" }, + { value: "gpt-oss-120b-medium", name: "GPT-OSS 120B (Medium)" }, + ], + }, + { + id: "thinking_level", + name: "Thinking Level", + category: "thought_level", + type: "select", + currentValue: "high", + options: [ + { value: "low", name: "Low" }, + { value: "medium", name: "Medium" }, + { value: "high", name: "High" }, + ], + }, + ], +} satisfies EffectAcpSchema.NewSessionResponse; diff --git a/apps/server/src/textGeneration/AntigravityTextGeneration.test.ts b/apps/server/src/textGeneration/AntigravityTextGeneration.test.ts index 395a24eeedc8d..107b1fec8735d 100644 --- a/apps/server/src/textGeneration/AntigravityTextGeneration.test.ts +++ b/apps/server/src/textGeneration/AntigravityTextGeneration.test.ts @@ -170,6 +170,7 @@ const makeFixture = Effect.fn("makeAntigravityTextGenerationFixture")(function* Effect.sync(() => { state.selectedModels.push(model); }), + setSessionModel: () => Effect.die("ACP 1.3 sessions select models through config options"), prompt: (request) => Effect.gen(function* () { state.prompts.push(request); diff --git a/apps/server/src/textGeneration/AntigravityTextGeneration.ts b/apps/server/src/textGeneration/AntigravityTextGeneration.ts index 670c2eb28d513..db7847a8dccc0 100644 --- a/apps/server/src/textGeneration/AntigravityTextGeneration.ts +++ b/apps/server/src/textGeneration/AntigravityTextGeneration.ts @@ -31,6 +31,7 @@ type AntigravityTextRuntime = Pick< | "getConfigOptions" | "getEvents" | "setModel" + | "setSessionModel" | "prompt" | "cancel" | "handleSessionUpdate" @@ -211,6 +212,7 @@ export const makeAntigravityTextGeneration = Effect.fn("makeAntigravityTextGener yield* runtime.setMode("default"); yield* applyAntigravityAcpModelSelection({ runtime, + models: started.sessionSetupResult.models, model: input.modelSelection.model, defaultModel: yield* options.defaultModel ?? Effect.undefined, mapError: (cause) => diff --git a/apps/web/src/components/settings/settingsSearch.ts b/apps/web/src/components/settings/settingsSearch.ts index 1bd8f1bb08e19..ffea18fa242fb 100644 --- a/apps/web/src/components/settings/settingsSearch.ts +++ b/apps/web/src/components/settings/settingsSearch.ts @@ -754,7 +754,7 @@ export const SETTINGS_SEARCH_ITEMS = [ title: "Providers", to: "/settings/providers", searchTerms: [ - "agents cli codex claude cursor grok fx opencode antigravity google sign in sign out install subscription instances authentication api key models configuration binary path config directory endpoint arguments environment variables display name accent color custom favorite hidden auto compact", + "agents cli codex claude cursor grok fx opencode antigravity google sign in sign out install subscription instances authentication api key models configuration binary path acp client name config directory endpoint arguments environment variables display name accent color custom favorite hidden auto compact", ], }, { diff --git a/docs/user/providers-antigravity.md b/docs/user/providers-antigravity.md index 0b1cd2f2c6da1..c1d48f1e5b9d9 100644 --- a/docs/user/providers-antigravity.md +++ b/docs/user/providers-antigravity.md @@ -72,6 +72,12 @@ The model list comes from your Antigravity account and can differ from other Antigravity apps. A resumed thread keeps its selected model. If access to that model ends, select another available model before continuing. +Google offers some models, such as Claude and GPT-OSS, only to ACP clients it +recognizes by name. To report a different name, set **ACP client name** in the +Antigravity provider settings, then refresh provider status to reload models. +Google can change which names it accepts. Clear the field to report T3 Code's +own name. + Use Antigravity's native `/plan` command for planning. T3 Code's separate Plan mode is unavailable. Tool approvals follow [Permission modes](./permission-modes.md). Questions with fixed choices still need one of the offered answers, even in diff --git a/packages/contracts/src/settings.ts b/packages/contracts/src/settings.ts index 74acdb2a8dd48..1acc29bf44172 100644 --- a/packages/contracts/src/settings.ts +++ b/packages/contracts/src/settings.ts @@ -795,12 +795,23 @@ export const AntigravitySettings = makeProviderSettingsSchema( providerSettingsForm: { placeholder: "Automatic", clearWhenEmpty: "persist" }, }), ), + acpClientName: TrimmedString.pipe( + Schema.withDecodingDefault(Effect.succeed("")), + Schema.annotateKey({ + title: "ACP client name", + description: + "Client name sent to the agent. Google offers some models only to specific clients.", + providerSettingsForm: { placeholder: "t3-code", clearWhenEmpty: "omit" }, + }), + ), customModels: Schema.Array(CustomModelSetting).pipe( Schema.withDecodingDefault(Effect.succeed([])), Schema.annotateKey({ providerSettingsForm: { hidden: true } }), ), }, - { order: ["authMethod", "apiKey", "gcpProject", "gcpLocation", "binaryPath"] }, + { + order: ["authMethod", "apiKey", "gcpProject", "gcpLocation", "binaryPath", "acpClientName"], + }, ); export type AntigravitySettings = typeof AntigravitySettings.Type; From 99e96e4f9dfae2736b1bc425368b125ca7420e4d Mon Sep 17 00:00:00 2001 From: mweinbach Date: Mon, 26 Oct 2026 11:44:18 -0400 Subject: [PATCH 3/4] fix(server): Antigravity config updates can add models to ungrouped sessions Co-authored-by: Cursor --- .../src/provider/AntigravityProvider.test.ts | 21 +++++++++++++++++++ .../src/provider/AntigravityProvider.ts | 17 +++++++-------- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/apps/server/src/provider/AntigravityProvider.test.ts b/apps/server/src/provider/AntigravityProvider.test.ts index 16240ce3037fe..23eb2ee81145f 100644 --- a/apps/server/src/provider/AntigravityProvider.test.ts +++ b/apps/server/src/provider/AntigravityProvider.test.ts @@ -388,6 +388,27 @@ it.layer(layerTest)("Antigravity provider snapshots", (it) => { ), ); + it.effect("lists models added by config updates to ungrouped sessions", () => + Effect.scoped( + Effect.gen(function* () { + const harness = yield* makeHarness(); + yield* harness.initialize; + yield* harness.provider.onSessionStarted(started); + + const configOptions = [ + { + ...modelConfig, + options: [...modelOptions, { value: "gemini-4-argon-high", name: "Gemini 4 Argon" }], + }, + ]; + yield* harness.provider.onConfigOptionsUpdated(configOptions); + expect((yield* harness.provider.snapshot.getSnapshot).models).toEqual( + buildAntigravityModelsFromSession({ configOptions }), + ); + }), + ), + ); + it.effect("does not guess a version before a custom launcher's first handshake", () => Effect.scoped( Effect.gen(function* () { diff --git a/apps/server/src/provider/AntigravityProvider.ts b/apps/server/src/provider/AntigravityProvider.ts index 8f2cc9cc0cb2d..9d05f0e323e85 100644 --- a/apps/server/src/provider/AntigravityProvider.ts +++ b/apps/server/src/provider/AntigravityProvider.ts @@ -116,8 +116,8 @@ function isMissingInstallation(error: EffectAcpErrors.AcpError | ProviderSetupEr interface AntigravityProviderState { readonly draft: ServerProviderDraft; readonly authRevision: number; - /** Config updates omit `models`, so keep the last session's concrete list. */ - readonly sessionModels: EffectAcpSchema.SessionModelState | null; + /** Config updates omit `models`, so keep a grouped session's concrete list. */ + readonly groupedModels: EffectAcpSchema.SessionModelState | null; } interface AntigravityProviderOptions { @@ -162,7 +162,7 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func const metadata = yield* SubscriptionRef.make({ draft: initialDraft, authRevision: 0, - sessionModels: null, + groupedModels: null, }); // Preserve disk-discovered skills when callbacks replace workspace commands; the registry will not rescan them. const discoveredSkills = new Map(); @@ -290,7 +290,7 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func const workspace = cwd ? workspaces.find((entry) => entry.cwd === cwd) : undefined; return { authRevision: state.authRevision + 1, - sessionModels: started.sessionSetupResult.models ?? null, + groupedModels: antigravityGroupedModels(started.sessionSetupResult) ?? null, draft: { ...draft, installed: true, @@ -331,10 +331,9 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func ) { yield* SubscriptionRef.update(metadata, (state) => { if (state.draft.auth.status !== "authenticated") return state; - const models = buildAntigravityModelsFromSession({ - configOptions, - models: antigravityGroupedModels({ configOptions, models: state.sessionModels }) ?? null, - }); + const models = buildAntigravityModelsFromSession( + state.groupedModels ? { models: state.groupedModels } : { configOptions }, + ); return { ...state, draft: { ...state.draft, models } }; }); }); @@ -383,7 +382,7 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func (state) => ({ authRevision: state.authRevision + 1, - sessionModels: null, + groupedModels: null, draft: { ...state.draft, auth: { status: "unauthenticated" }, From 6556f3eb36ad4463db63c1feca2f175537e6b3a0 Mon Sep 17 00:00:00 2001 From: mweinbach Date: Mon, 26 Oct 2026 12:00:02 -0400 Subject: [PATCH 4/4] fix(server): Antigravity marks the selected ACP 1.4 model as default Co-authored-by: Cursor --- .../Adapters/AntigravityAdapterV2.ts | 7 ++++- .../src/provider/AntigravityProvider.test.ts | 25 +++++++++++++++++ .../src/provider/AntigravityProvider.ts | 27 +++++++++++++++++++ .../src/provider/Drivers/AntigravityDriver.ts | 1 + 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/apps/server/src/orchestration-v2/Adapters/AntigravityAdapterV2.ts b/apps/server/src/orchestration-v2/Adapters/AntigravityAdapterV2.ts index 2ddb678926d44..0d1e13d771d8b 100644 --- a/apps/server/src/orchestration-v2/Adapters/AntigravityAdapterV2.ts +++ b/apps/server/src/orchestration-v2/Adapters/AntigravityAdapterV2.ts @@ -78,6 +78,7 @@ export interface AntigravityAdapterV2Options { cwd: string, ) => Effect.Effect; readonly onSessionEvent?: AcpAdapterV2Flavor["onSessionEvent"]; + readonly onModelSelected?: (modelId: string) => Effect.Effect; readonly nativeLogging?: Parameters[0]["nativeLogging"]; readonly continuationRequests?: Parameters[0]["continuationRequests"]; } @@ -176,7 +177,7 @@ export function makeAntigravityAcpAdapterFlavor( modelSelection, }) { const defaultModel = yield* options.defaultModel; - return yield* applyAntigravityAcpModelSelection({ + const selected = yield* applyAntigravityAcpModelSelection({ runtime, models: startResult.sessionSetupResult.models, model: @@ -184,6 +185,10 @@ export function makeAntigravityAcpAdapterFlavor( defaultModel, mapError: (cause) => cause, }); + if (selected !== undefined && options.onModelSelected) { + yield* options.onModelSelected(selected); + } + return selected; }), sessionModeForPolicy: (policy) => antigravityPermissionMode(policy.runtimeMode), clientFileSystem: { diff --git a/apps/server/src/provider/AntigravityProvider.test.ts b/apps/server/src/provider/AntigravityProvider.test.ts index 23eb2ee81145f..48dbd57a3ec03 100644 --- a/apps/server/src/provider/AntigravityProvider.test.ts +++ b/apps/server/src/provider/AntigravityProvider.test.ts @@ -388,6 +388,31 @@ it.layer(layerTest)("Antigravity provider snapshots", (it) => { ), ); + it.effect("defaults to the concrete model a grouped session selected", () => + Effect.scoped( + Effect.gen(function* () { + const harness = yield* makeHarness(); + yield* harness.initialize; + yield* harness.provider.onSessionStarted({ + ...started, + sessionSetupResult: antigravity143Session, + }); + yield* harness.provider.onModelSelected("claude-sonnet-5-5-low"); + yield* harness.provider.onConfigOptionsUpdated( + antigravity143Session.configOptions.map((option) => + option.id === "model" + ? { ...option, currentValue: "claude-sonnet-5-5" } + : { ...option, currentValue: "low" }, + ), + ); + const models = (yield* harness.provider.snapshot.getSnapshot).models; + expect(models.filter((model) => model.isDefault).map((model) => model.slug)).toEqual([ + "claude-sonnet-5-5-low", + ]); + }), + ), + ); + it.effect("lists models added by config updates to ungrouped sessions", () => Effect.scoped( Effect.gen(function* () { diff --git a/apps/server/src/provider/AntigravityProvider.ts b/apps/server/src/provider/AntigravityProvider.ts index 9d05f0e323e85..839f5c13e7c01 100644 --- a/apps/server/src/provider/AntigravityProvider.ts +++ b/apps/server/src/provider/AntigravityProvider.ts @@ -338,6 +338,32 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func }); }); + // Grouped config updates name only the family and thinking level. + const onModelSelected = Effect.fn("AntigravityProvider.onModelSelected")(function* ( + modelId: string, + ) { + yield* SubscriptionRef.update(metadata, (state) => { + const grouped = state.groupedModels; + if ( + state.draft.auth.status !== "authenticated" || + !grouped || + grouped.currentModelId === modelId || + !grouped.availableModels.some((model) => model.modelId === modelId) + ) { + return state; + } + const groupedModels = { ...grouped, currentModelId: modelId }; + return { + ...state, + groupedModels, + draft: { + ...state.draft, + models: buildAntigravityModelsFromSession({ models: groupedModels }), + }, + }; + }); + }); + const onAvailableCommands = Effect.fn("AntigravityProvider.onAvailableCommands")(function* ( commands: ReadonlyArray, cwd?: string, @@ -433,6 +459,7 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func snapshot: { ...managed, getSnapshot }, onSessionStarted, onConfigOptionsUpdated, + onModelSelected, onAvailableCommands, onSignedOut: clearAccountMetadata(), onAuthRequired: clearAccountMetadata(), diff --git a/apps/server/src/provider/Drivers/AntigravityDriver.ts b/apps/server/src/provider/Drivers/AntigravityDriver.ts index 29ba0689a896c..6f9ab4a584a35 100644 --- a/apps/server/src/provider/Drivers/AntigravityDriver.ts +++ b/apps/server/src/provider/Drivers/AntigravityDriver.ts @@ -428,6 +428,7 @@ export const AntigravityDriver: ProviderDriver< ? provider.onAvailableCommands(event.availableCommands) : Effect.void; }, + onModelSelected: provider.onModelSelected, continuationRequests, nativeLogging: (threadId) => makeNativeLogger({