| author | |
| committer | |
| log | baf67b6e3accd48d510fd0d39a4e6b978a1eea80 |
| tree | 16f54313f76035e495878ff6ca735fc9ad2dd307 |
| parent | f25e4428961982e3935300cfd3c78f7d0fac4ee9 |
| signature | Signed by PGP key B5690EEEBB952194 |
10 files changed, 113 insertions(+), 10 deletions(-)
apps/server/src/provider/Drivers/AntigravityDriver.ts+4| ... | @@ -233,6 +233,9 @@ export const AntigravityDriver: ProviderDriver<AntigravitySettings, AntigravityD | ... | @@ -233,6 +233,9 @@ export const AntigravityDriver: ProviderDriver<AntigravitySettings, AntigravityD |
| 233 | if (event._tag === "EventStreamBarrier") { | 233 | if (event._tag === "EventStreamBarrier") { |
| 234 | return Deferred.succeed(event.acknowledge, undefined).pipe(Effect.asVoid); | 234 | return Deferred.succeed(event.acknowledge, undefined).pipe(Effect.asVoid); |
| 235 | } | 235 | } |
| 236 | if (event._tag === "ConfigOptionsUpdated") { | ||
| 237 | return provider.onConfigOptionsUpdated(event.configOptions); | ||
| 238 | } | ||
| 236 | return event._tag === "AvailableCommandsUpdated" | 239 | return event._tag === "AvailableCommandsUpdated" |
| 237 | ? provider.onAvailableCommands(event.availableCommands) | 240 | ? provider.onAvailableCommands(event.availableCommands) |
| 238 | : Effect.void; | 241 | : Effect.void; |
| ... | @@ -299,6 +302,7 @@ export const AntigravityDriver: ProviderDriver<AntigravitySettings, AntigravityD | ... | @@ -299,6 +302,7 @@ export const AntigravityDriver: ProviderDriver<AntigravitySettings, AntigravityD |
| 299 | withProcess: authFlow.withProcess, | 302 | withProcess: authFlow.withProcess, |
| 300 | defaultModel, | 303 | defaultModel, |
| 301 | onSessionStarted: provider.onSessionStarted, | 304 | onSessionStarted: provider.onSessionStarted, |
| 305 | onConfigOptionsUpdated: provider.onConfigOptionsUpdated, | ||
| 302 | onAvailableCommands: provider.onAvailableCommands, | 306 | onAvailableCommands: provider.onAvailableCommands, |
| 303 | onAuthRequired: provider.onAuthRequired, | 307 | onAuthRequired: provider.onAuthRequired, |
| 304 | ...(loggers.native ? { nativeEventLogger: loggers.native } : {}), | 308 | ...(loggers.native ? { nativeEventLogger: loggers.native } : {}), |
apps/server/src/provider/Layers/AntigravityAdapter.test.ts+8| ... | @@ -297,6 +297,7 @@ it.layer(layer)("AntigravityAdapter", (it) => { | ... | @@ -297,6 +297,7 @@ it.layer(layer)("AntigravityAdapter", (it) => { |
| 297 | ); | 297 | ); |
| 298 | const requestLog = path.join(cwd, "requests.ndjson"); | 298 | const requestLog = path.join(cwd, "requests.ndjson"); |
| 299 | const commands: string[] = []; | 299 | const commands: string[] = []; |
| 300 | const modelSelections: string[] = []; | ||
| 300 | const observed: ProviderRuntimeEvent[] = []; | 301 | const observed: ProviderRuntimeEvent[] = []; |
| 301 | const completed = yield* Deferred.make<void>(); | 302 | const completed = yield* Deferred.make<void>(); |
| 302 | const adapter = yield* makeAntigravityAdapter(decodeSettings({ enabled: true }), { | 303 | const adapter = yield* makeAntigravityAdapter(decodeSettings({ enabled: true }), { |
| ... | @@ -322,6 +323,11 @@ it.layer(layer)("AntigravityAdapter", (it) => { | ... | @@ -322,6 +323,11 @@ it.layer(layer)("AntigravityAdapter", (it) => { |
| 322 | Effect.sync(() => { | 323 | Effect.sync(() => { |
| 323 | commands.push(...available.map((command) => command.name)); | 324 | commands.push(...available.map((command) => command.name)); |
| 324 | }), | 325 | }), |
| 326 | onConfigOptionsUpdated: (configOptions) => | ||
| 327 | Effect.sync(() => { | ||
| 328 | const model = configOptions.find((option) => option.category === "model"); | ||
| 329 | if (model?.type === "select") modelSelections.push(model.currentValue); | ||
| 330 | }), | ||
| 325 | }); | 331 | }); |
| 326 | yield* adapter.streamEvents.pipe( | 332 | yield* adapter.streamEvents.pipe( |
| 327 | Stream.runForEach((event) => | 333 | Stream.runForEach((event) => |
| ... | @@ -350,6 +356,8 @@ it.layer(layer)("AntigravityAdapter", (it) => { | ... | @@ -350,6 +356,8 @@ it.layer(layer)("AntigravityAdapter", (it) => { |
| 350 | yield* adapter.sendTurn({ threadId, input: "Reply with one short line." }); | 356 | yield* adapter.sendTurn({ threadId, input: "Reply with one short line." }); |
| 351 | yield* Deferred.await(completed); | 357 | yield* Deferred.await(completed); |
| 352 | expect(commands).toEqual(["plan", "logout", "plan", "logout"]); | 358 | expect(commands).toEqual(["plan", "logout", "plan", "logout"]); |
| 359 | expect(modelSelections.length).toBeGreaterThan(0); | ||
| 360 | expect(modelSelections.every((model) => model === nativeAlternative)).toBe(true); | ||
| 353 | expect( | 361 | expect( |
| 354 | observed | 362 | observed |
| 355 | .filter((event) => event.type === "content.delta") | 363 | .filter((event) => event.type === "content.delta") |
apps/server/src/provider/Layers/AntigravityAdapter.ts+6| ... | @@ -133,6 +133,9 @@ export interface AntigravityAdapterOptions { | ... | @@ -133,6 +133,9 @@ export interface AntigravityAdapterOptions { |
| 133 | commands: ReadonlyArray<EffectAcpSchema.AvailableCommand>, | 133 | commands: ReadonlyArray<EffectAcpSchema.AvailableCommand>, |
| 134 | cwd: string, | 134 | cwd: string, |
| 135 | ) => Effect.Effect<void>; | 135 | ) => Effect.Effect<void>; |
| 136 | readonly onConfigOptionsUpdated?: ( | ||
| 137 | configOptions: ReadonlyArray<EffectAcpSchema.SessionConfigOption>, | ||
| 138 | ) => Effect.Effect<void>; | ||
| 136 | readonly onAuthRequired?: Effect.Effect<void>; | 139 | readonly onAuthRequired?: Effect.Effect<void>; |
| 137 | /** Model the provider default alias selects, when the account offers it. */ | 140 | /** Model the provider default alias selects, when the account offers it. */ |
| 138 | readonly defaultModel?: Effect.Effect<string | undefined>; | 141 | readonly defaultModel?: Effect.Effect<string | undefined>; |
| ... | @@ -503,6 +506,9 @@ export const makeAntigravityAdapter = Effect.fn("makeAntigravityAdapter")(functi | ... | @@ -503,6 +506,9 @@ export const makeAntigravityAdapter = Effect.fn("makeAntigravityAdapter")(functi |
| 503 | case "AvailableCommandsUpdated": | 506 | case "AvailableCommandsUpdated": |
| 504 | yield* options.onAvailableCommands?.(event.availableCommands, context.cwd) ?? Effect.void; | 507 | yield* options.onAvailableCommands?.(event.availableCommands, context.cwd) ?? Effect.void; |
| 505 | return; | 508 | return; |
| 509 | case "ConfigOptionsUpdated": | ||
| 510 | yield* options.onConfigOptionsUpdated?.(event.configOptions) ?? Effect.void; | ||
| 511 | return; | ||
| 506 | case "ConnectionTerminated": | 512 | case "ConnectionTerminated": |
| 507 | context.stopped = true; | 513 | context.stopped = true; |
| 508 | context.disconnected = true; | 514 | context.disconnected = true; |
apps/server/src/provider/Layers/AntigravityProvider.test.ts+35-2| ... | @@ -175,7 +175,6 @@ describe("Antigravity model catalog", () => { | ... | @@ -175,7 +175,6 @@ describe("Antigravity model catalog", () => { |
| 175 | 175 | ||
| 176 | it("uses legacy session models only when model config is absent", () => { | 176 | it("uses legacy session models only when model config is absent", () => { |
| 177 | const fromLegacy = buildAntigravityModelsFromSession({ | 177 | const fromLegacy = buildAntigravityModelsFromSession({ |
| 178 | sessionId: "legacy-session", | ||
| 179 | models: sessionSetupResult.models, | 178 | models: sessionSetupResult.models, |
| 180 | }); | 179 | }); |
| 181 | expect(fromLegacy).toEqual(buildAntigravityModelsFromSession(sessionSetupResult)); | 180 | expect(fromLegacy).toEqual(buildAntigravityModelsFromSession(sessionSetupResult)); |
| ... | @@ -189,7 +188,6 @@ describe("Antigravity model catalog", () => { | ... | @@ -189,7 +188,6 @@ describe("Antigravity model catalog", () => { |
| 189 | 188 | ||
| 190 | it("flattens native option groups without combining distinct model IDs", () => { | 189 | it("flattens native option groups without combining distinct model IDs", () => { |
| 191 | const models = buildAntigravityModelsFromSession({ | 190 | const models = buildAntigravityModelsFromSession({ |
| 192 | sessionId: "grouped-session", | ||
| 193 | configOptions: [ | 191 | configOptions: [ |
| 194 | { | 192 | { |
| 195 | ...modelConfig, | 193 | ...modelConfig, |
| ... | @@ -356,7 +354,9 @@ it.layer(testLayer)("Antigravity provider snapshots", (it) => { | ... | @@ -356,7 +354,9 @@ it.layer(testLayer)("Antigravity provider snapshots", (it) => { |
| 356 | supportsTextGeneration: false, | 354 | supportsTextGeneration: false, |
| 357 | }); | 355 | }); |
| 358 | yield* harness.provider.onAvailableCommands(commands, "/workspace"); | 356 | yield* harness.provider.onAvailableCommands(commands, "/workspace"); |
| 357 | yield* harness.provider.onConfigOptionsUpdated([modelConfig]); | ||
| 359 | expect((yield* harness.provider.snapshotForCwd("/workspace")).slashCommands).toEqual([]); | 358 | expect((yield* harness.provider.snapshotForCwd("/workspace")).slashCommands).toEqual([]); |
| 359 | expect((yield* harness.provider.snapshot.getSnapshot).models).toEqual([]); | ||
| 360 | } | 360 | } |
| 361 | const refreshed = yield* harness.provider.snapshot.refresh; | 361 | const refreshed = yield* harness.provider.snapshot.refresh; |
| 362 | expect(refreshed.auth.status).toBe("unauthenticated"); | 362 | expect(refreshed.auth.status).toBe("unauthenticated"); |
| ... | @@ -365,6 +365,39 @@ it.layer(testLayer)("Antigravity provider snapshots", (it) => { | ... | @@ -365,6 +365,39 @@ it.layer(testLayer)("Antigravity provider snapshots", (it) => { |
| 365 | ), | 365 | ), |
| 366 | ); | 366 | ); |
| 367 | 367 | ||
| 368 | it.effect("replaces live model choices and accepts an empty catalog", () => | ||
| 369 | Effect.scoped( | ||
| 370 | Effect.gen(function* () { | ||
| 371 | const harness = yield* makeHarness(); | ||
| 372 | yield* harness.initialize; | ||
| 373 | yield* harness.provider.onSessionStarted(started, "/workspace"); | ||
| 374 | yield* harness.provider.onAvailableCommands(commands, "/workspace"); | ||
| 375 | const before = yield* harness.provider.snapshot.getSnapshot; | ||
| 376 | const configOptions = [ | ||
| 377 | { | ||
| 378 | ...modelConfig, | ||
| 379 | currentValue: "gemini-3.8-flash-high", | ||
| 380 | options: modelOptions.slice(0, 3), | ||
| 381 | }, | ||
| 382 | ]; | ||
| 383 | const nextSnapshot = yield* Stream.toPull( | ||
| 384 | harness.provider.snapshot.streamChanges.pipe( | ||
| 385 | Stream.filter((snapshot) => snapshot.models.length === 3), | ||
| 386 | ), | ||
| 387 | ); | ||
| 388 | yield* harness.provider.onConfigOptionsUpdated(configOptions); | ||
| 389 | expect((yield* nextSnapshot)[0]).toMatchObject({ | ||
| 390 | models: buildAntigravityModelsFromSession({ configOptions }), | ||
| 391 | auth: before.auth, | ||
| 392 | workspaceSnapshots: before.workspaceSnapshots, | ||
| 393 | slashCommands: commands, | ||
| 394 | }); | ||
| 395 | yield* harness.provider.onConfigOptionsUpdated([]); | ||
| 396 | expect((yield* harness.provider.snapshot.getSnapshot).models).toEqual([]); | ||
| 397 | }), | ||
| 398 | ), | ||
| 399 | ); | ||
| 400 | |||
| 368 | it.effect("replaces one account's catalog instead of combining accounts", () => | 401 | it.effect("replaces one account's catalog instead of combining accounts", () => |
| 369 | Effect.scoped( | 402 | Effect.scoped( |
| 370 | Effect.gen(function* () { | 403 | Effect.gen(function* () { |
apps/server/src/provider/Layers/AntigravityProvider.ts+15-1| ... | @@ -37,7 +37,10 @@ const SIGN_IN_MESSAGE = "Sign in with Google to use Antigravity."; | ... | @@ -37,7 +37,10 @@ const SIGN_IN_MESSAGE = "Sign in with Google to use Antigravity."; |
| 37 | const AUTH_UNCHECKED_MESSAGE = | 37 | const AUTH_UNCHECKED_MESSAGE = |
| 38 | "Antigravity is installed. Google account access is not checked yet."; | 38 | "Antigravity is installed. Google account access is not checked yet."; |
| 39 | 39 | ||
| 40 | type SessionSetupResult = AcpSessionRuntimeStartResult["sessionSetupResult"]; | 40 | type SessionSetupResult = Pick< |
| 41 | AcpSessionRuntimeStartResult["sessionSetupResult"], | ||
| 42 | "configOptions" | "models" | ||
| 43 | >; | ||
| 41 | 44 | ||
| 42 | /** Keep the native model IDs, including model-specific thinking levels. */ | 45 | /** Keep the native model IDs, including model-specific thinking levels. */ |
| 43 | export function buildAntigravityModelsFromSession( | 46 | export function buildAntigravityModelsFromSession( |
| ... | @@ -299,6 +302,16 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func | ... | @@ -299,6 +302,16 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func |
| 299 | }); | 302 | }); |
| 300 | }); | 303 | }); |
| 301 | 304 | ||
| 305 | const onConfigOptionsUpdated = Effect.fn("AntigravityProvider.onConfigOptionsUpdated")(function* ( | ||
| 306 | configOptions: ReadonlyArray<EffectAcpSchema.SessionConfigOption>, | ||
| 307 | ) { | ||
| 308 | const models = buildAntigravityModelsFromSession({ configOptions }); | ||
| 309 | yield* SubscriptionRef.update(metadata, (state) => { | ||
| 310 | if (state.draft.auth.status !== "authenticated") return state; | ||
| 311 | return { ...state, draft: { ...state.draft, models } }; | ||
| 312 | }); | ||
| 313 | }); | ||
| 314 | |||
| 302 | const onAvailableCommands = Effect.fn("AntigravityProvider.onAvailableCommands")(function* ( | 315 | const onAvailableCommands = Effect.fn("AntigravityProvider.onAvailableCommands")(function* ( |
| 303 | commands: ReadonlyArray<EffectAcpSchema.AvailableCommand>, | 316 | commands: ReadonlyArray<EffectAcpSchema.AvailableCommand>, |
| 304 | cwd?: string, | 317 | cwd?: string, |
| ... | @@ -373,6 +386,7 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func | ... | @@ -373,6 +386,7 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func |
| 373 | return { | 386 | return { |
| 374 | snapshot: { ...managed, getSnapshot }, | 387 | snapshot: { ...managed, getSnapshot }, |
| 375 | onSessionStarted, | 388 | onSessionStarted, |
| 389 | onConfigOptionsUpdated, | ||
| 376 | onAvailableCommands, | 390 | onAvailableCommands, |
| 377 | onSignedOut: clearAccountMetadata(), | 391 | onSignedOut: clearAccountMetadata(), |
| 378 | onAuthRequired: clearAccountMetadata(), | 392 | onAuthRequired: clearAccountMetadata(), |
apps/server/src/provider/acp/AcpJsonRpcConnection.test.ts+18| ... | @@ -69,11 +69,15 @@ describe("AcpSessionRuntime", () => { | ... | @@ -69,11 +69,15 @@ describe("AcpSessionRuntime", () => { |
| 69 | expect(events.map((event) => event._tag)).toEqual([ | 69 | expect(events.map((event) => event._tag)).toEqual([ |
| 70 | "AvailableCommandsUpdated", | 70 | "AvailableCommandsUpdated", |
| 71 | "ModeChanged", | 71 | "ModeChanged", |
| 72 | "ConfigOptionsUpdated", | ||
| 72 | ]); | 73 | ]); |
| 73 | expect(events[0]).toMatchObject({ | 74 | expect(events[0]).toMatchObject({ |
| 74 | availableCommands: [{ name: "plan", description: "Native command" }], | 75 | availableCommands: [{ name: "plan", description: "Native command" }], |
| 75 | }); | 76 | }); |
| 76 | expect(yield* runtime.getModeState).toMatchObject({ currentModeId: "code" }); | 77 | expect(yield* runtime.getModeState).toMatchObject({ currentModeId: "code" }); |
| 78 | expect(events[2]).toMatchObject({ | ||
| 79 | configOptions: yield* runtime.getConfigOptions, | ||
| 80 | }); | ||
| 77 | expect( | 81 | expect( |
| 78 | (yield* runtime.getConfigOptions).find((option) => option.category === "model"), | 82 | (yield* runtime.getConfigOptions).find((option) => option.category === "model"), |
| 79 | ).toMatchObject({ currentValue: "gpt-5.4" }); | 83 | ).toMatchObject({ currentValue: "gpt-5.4" }); |
| ... | @@ -81,6 +85,20 @@ describe("AcpSessionRuntime", () => { | ... | @@ -81,6 +85,20 @@ describe("AcpSessionRuntime", () => { |
| 81 | ); | 85 | ); |
| 82 | } | 86 | } |
| 83 | 87 | ||
| 88 | it.effect("publishes model changes returned by a config request and live notifications", () => | ||
| 89 | Effect.gen(function* () { | ||
| 90 | const runtime = yield* AcpSessionRuntime.make(mockRuntimeOptions); | ||
| 91 | yield* runtime.start(); | ||
| 92 | const updates = yield* Stream.toPull( | ||
| 93 | runtime.getEvents().pipe(Stream.filter((event) => event._tag === "ConfigOptionsUpdated")), | ||
| 94 | ); | ||
| 95 | const selected = yield* runtime.setConfigOption("model", "composer-2"); | ||
| 96 | expect((yield* updates)[0]?.configOptions).toEqual(selected.configOptions); | ||
| 97 | yield* runtime.request("_test/startup-metadata", {}); | ||
| 98 | expect((yield* updates)[0]?.configOptions).toEqual(yield* runtime.getConfigOptions); | ||
| 99 | }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), | ||
| 100 | ); | ||
| 101 | |||
| 84 | it.effect("awaits native resume instead of using the load replay idle fallback", () => | 102 | it.effect("awaits native resume instead of using the load replay idle fallback", () => |
| 85 | Effect.gen(function* () { | 103 | Effect.gen(function* () { |
| 86 | const resumeStarted = yield* Deferred.make<void>(); | 104 | const resumeStarted = yield* Deferred.make<void>(); |
apps/server/src/provider/acp/AcpRuntimeModel.ts+13| ... | @@ -90,6 +90,11 @@ export type AcpParsedSessionEvent = | ... | @@ -90,6 +90,11 @@ export type AcpParsedSessionEvent = |
| 90 | readonly availableCommands: ReadonlyArray<EffectAcpSchema.AvailableCommand>; | 90 | readonly availableCommands: ReadonlyArray<EffectAcpSchema.AvailableCommand>; |
| 91 | readonly rawPayload: unknown; | 91 | readonly rawPayload: unknown; |
| 92 | } | 92 | } |
| 93 | | { | ||
| 94 | readonly _tag: "ConfigOptionsUpdated"; | ||
| 95 | readonly configOptions: ReadonlyArray<EffectAcpSchema.SessionConfigOption>; | ||
| 96 | readonly rawPayload: unknown; | ||
| 97 | } | ||
| 93 | | { | 98 | | { |
| 94 | readonly _tag: "AssistantItemStarted"; | 99 | readonly _tag: "AssistantItemStarted"; |
| 95 | readonly itemId: string; | 100 | readonly itemId: string; |
| ... | @@ -788,6 +793,14 @@ export function parseSessionUpdateEvent(params: EffectAcpSchema.SessionNotificat | ... | @@ -788,6 +793,14 @@ export function parseSessionUpdateEvent(params: EffectAcpSchema.SessionNotificat |
| 788 | let modeId: string | undefined; | 793 | let modeId: string | undefined; |
| 789 | 794 | ||
| 790 | switch (upd.sessionUpdate) { | 795 | switch (upd.sessionUpdate) { |
| 796 | case "config_option_update": { | ||
| 797 | events.push({ | ||
| 798 | _tag: "ConfigOptionsUpdated", | ||
| 799 | configOptions: upd.configOptions, | ||
| 800 | rawPayload: params, | ||
| 801 | }); | ||
| 802 | break; | ||
| 803 | } | ||
| 791 | case "available_commands_update": { | 804 | case "available_commands_update": { |
| 792 | events.push({ | 805 | events.push({ |
| 793 | _tag: "AvailableCommandsUpdated", | 806 | _tag: "AvailableCommandsUpdated", |
apps/server/src/provider/acp/AcpSessionRuntime.ts+11-7| ... | @@ -615,13 +615,17 @@ export const make = ( | ... | @@ -615,13 +615,17 @@ export const make = ( |
| 615 | }); | 615 | }); |
| 616 | }); | 616 | }); |
| 617 | 617 | ||
| 618 | const updateConfigOptions = ( | 618 | const updateConfigOptions = Effect.fn("AcpSessionRuntime.updateConfigOptions")(function* ( |
| 619 | response: | 619 | response: EffectAcpSchema.SetSessionConfigOptionResponse, |
| 620 | | EffectAcpSchema.SetSessionConfigOptionResponse | 620 | ) { |
| 621 | | EffectAcpSchema.LoadSessionResponse | 621 | const configOptions = sessionConfigOptionsFromSetup(response); |
| 622 | | EffectAcpSchema.NewSessionResponse | 622 | yield* Ref.set(configOptionsRef, configOptions); |
| 623 | | EffectAcpSchema.ResumeSessionResponse, | 623 | yield* Queue.offer(eventQueue, { |
| 624 | ): Effect.Effect<void> => Ref.set(configOptionsRef, sessionConfigOptionsFromSetup(response)); | 624 | _tag: "ConfigOptionsUpdated", |
| 625 | configOptions, | ||
| 626 | rawPayload: response, | ||
| 627 | }); | ||
| 628 | }); | ||
| 625 | 629 | ||
| 626 | const updateCurrentModeId = (modeId: string): Effect.Effect<void> => | 630 | const updateCurrentModeId = (modeId: string): Effect.Effect<void> => |
| 627 | Ref.update(modeStateRef, (current) => | 631 | Ref.update(modeStateRef, (current) => |
docs/internals/providers.md+2| ... | @@ -168,6 +168,8 @@ Account access starts unknown and becomes authenticated after successful session | ... | @@ -168,6 +168,8 @@ Account access starts unknown and becomes authenticated after successful session |
| 168 | including an explicit model refresh. | 168 | including an explicit model refresh. |
| 169 | The [provider snapshot][antigravity-provider] takes models and commands from setup and native | 169 | The [provider snapshot][antigravity-provider] takes models and commands from setup and native |
| 170 | updates. It preserves returned Gemini model IDs, labels, order, and thinking-level choices. | 170 | updates. It preserves returned Gemini model IDs, labels, order, and thinking-level choices. |
| 171 | ACP `config_option_update` notifications and `session/set_config_option` responses replace | ||
| 172 | the instance's model catalog. Child session notifications do not change the root catalog. | ||
| 171 | The registry treats a successful empty catalog as authoritative and clears cached metadata | 173 | The registry treats a successful empty catalog as authoritative and clears cached metadata |
| 172 | after sign-out. It must not retain a previous account's models. Cached models do not prove | 174 | after sign-out. It must not retain a previous account's models. Cached models do not prove |
| 173 | current access. The auth response does not supply an email, plan tier, or reliable quota. | 175 | current access. The auth response does not supply an email, plan tier, or reliable quota. |
docs/user/providers-antigravity.md+1| ... | @@ -107,6 +107,7 @@ installations. Clear **Binary path** to use managed installation controls. | ... | @@ -107,6 +107,7 @@ installations. Clear **Binary path** to use managed installation controls. |
| 107 | The current official ACP exposes Gemini models only. T3 Code uses the model IDs and names | 107 | The current official ACP exposes Gemini models only. T3 Code uses the model IDs and names |
| 108 | returned for your account, including any model choices with different thinking levels. Models | 108 | returned for your account, including any model choices with different thinking levels. Models |
| 109 | available in other Antigravity apps might not be available through this agent. | 109 | available in other Antigravity apps might not be available through this agent. |
| 110 | The model picker updates when a running session reports new model choices. | ||
| 110 | 111 | ||
| 111 | New threads use Gemini 3.8 Flash (High) when your account offers it. Older Gemini generations | 112 | New threads use Gemini 3.8 Flash (High) when your account offers it. Older Gemini generations |
| 112 | stay available under **Legacy models** in the picker. | 113 | stay available under **Legacy models** in the picker. |