diff --git a/apps/server/src/orchestration-v2/Adapters/AntigravityAdapterV2.ts b/apps/server/src/orchestration-v2/Adapters/AntigravityAdapterV2.ts index a37781debe460..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"]; } @@ -172,16 +173,22 @@ 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({ + const selected = yield* applyAntigravityAcpModelSelection({ runtime, + models: startResult.sessionSetupResult.models, model: modelSelection.model === ANTIGRAVITY_DEFAULT_MODEL ? undefined : modelSelection.model, 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 ade033551f655..48dbd57a3ec03 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,81 @@ 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("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* () { + 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 c6809c3577132..839f5c13e7c01 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 a grouped session's concrete list. */ + readonly groupedModels: 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, + groupedModels: 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, + groupedModels: antigravityGroupedModels(started.sessionSetupResult) ?? null, draft: { ...draft, installed: true, @@ -324,13 +329,41 @@ 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( + state.groupedModels ? { models: state.groupedModels } : { configOptions }, + ); return { ...state, draft: { ...state.draft, models } }; }); }); + // 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, @@ -375,6 +408,7 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func (state) => ({ authRevision: state.authRevision + 1, + groupedModels: null, draft: { ...state.draft, auth: { status: "unauthenticated" }, @@ -425,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.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..6f9ab4a584a35 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({ @@ -425,6 +428,7 @@ export const AntigravityDriver: ProviderDriver< ? provider.onAvailableCommands(event.availableCommands) : Effect.void; }, + onModelSelected: provider.onModelSelected, continuationRequests, nativeLogging: (threadId) => makeNativeLogger({ 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/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 }, }, ], ]); 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;