Skip to content

Commit b557c84

Browse files
committed
fix(web): resume Antigravity threads without repeated sign-in
1 parent 09d13de commit b557c84

5 files changed

Lines changed: 76 additions & 15 deletions

File tree

‎apps/web/src/components/ChatView.logic.test.ts‎

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
ANTIGRAVITY_DEFAULT_MODEL,
23
CheckpointRef,
34
EnvironmentId,
45
MessageId,
@@ -793,14 +794,20 @@ describe("resolveComposerProviderSelection", () => {
793794
);
794795
});
795796

796-
it("blocks sends until Antigravity confirms authentication", () => {
797+
it("lets Antigravity check saved credentials when resuming after a restart", () => {
797798
const provider = entry("antigravity", "google_work", {
799+
status: "warning",
798800
auth: { status: "unknown" },
799-
models: catalogModels,
801+
models: [],
800802
}).snapshot;
801803

802-
expect(getAntigravitySendBlockReason(provider, "gemini-pro")).toBe(
803-
"Sign in to Antigravity in provider settings before sending.",
804+
expect(getAntigravitySendBlockReason(provider, "gemini-pro")).toBeNull();
805+
expect(getAntigravitySendBlockReason(provider, ANTIGRAVITY_DEFAULT_MODEL)).toBeNull();
806+
expect(
807+
getAntigravitySendBlockReason({ ...provider, models: catalogModels }, "gemini-pro"),
808+
).toBeNull();
809+
expect(getAntigravitySendBlockReason(provider, "")).toBe(
810+
"Choose an Antigravity model before sending.",
804811
);
805812
});
806813

‎apps/web/src/components/ChatView.logic.ts‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -421,14 +421,17 @@ export function getAntigravitySendBlockReason(
421421
if (!provider.installed) {
422422
return "Install Antigravity in provider settings before sending.";
423423
}
424-
if (provider.auth.status !== "authenticated") {
424+
if (provider.auth.status === "unauthenticated") {
425425
return "Sign in to Antigravity in provider settings before sending.";
426426
}
427+
const slug = model.trim();
428+
if (slug.length === 0) return "Choose an Antigravity model before sending.";
429+
// A restart clears the account status and catalog. Session startup checks
430+
// saved credentials and validates the model before sending the prompt.
431+
if (provider.auth.status === "unknown") return null;
427432
if (provider.models.length === 0) {
428433
return "Refresh Antigravity models in provider settings before sending.";
429434
}
430-
const slug = model.trim();
431-
if (slug.length === 0) return "Choose an Antigravity model before sending.";
432435
// A saved model that left the catalog is kept in the picker as unavailable
433436
// so the user sees what the thread used. The server rejects it at turn
434437
// start, so block here unless the provider is in an error state, where a

‎apps/web/src/components/chat/ProviderStatusBanner.test.tsx‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,42 @@ function warningProvider(): ServerProvider {
2828
}
2929

3030
describe("ProviderStatusBanner", () => {
31+
it("waits for an Antigravity auth result before showing a sign-in warning", () => {
32+
const status: ServerProvider = {
33+
...warningProvider(),
34+
instanceId: ProviderInstanceId.make("google_work"),
35+
driver: ProviderDriverKind.make("antigravity"),
36+
auth: { status: "unknown" },
37+
message: "Antigravity is installed. Google account access is not checked yet.",
38+
};
39+
40+
expect(shouldShowProviderStatusBanner(status, null)).toBe(false);
41+
expect(
42+
shouldShowProviderStatusBanner(
43+
{
44+
...status,
45+
auth: { status: "unauthenticated" },
46+
message: "Sign in with Google to use Antigravity.",
47+
},
48+
null,
49+
),
50+
).toBe(true);
51+
});
52+
53+
it("shows Antigravity installation and startup failures before auth is checked", () => {
54+
const status: ServerProvider = {
55+
...warningProvider(),
56+
driver: ProviderDriverKind.make("antigravity"),
57+
auth: { status: "unknown" },
58+
};
59+
60+
expect(shouldShowProviderStatusBanner({ ...status, installed: false }, null)).toBe(true);
61+
expect(shouldShowProviderStatusBanner({ ...status, status: "error" }, null)).toBe(true);
62+
expect(
63+
shouldShowProviderStatusBanner({ ...status, driver: ProviderDriverKind.make("codex") }, null),
64+
).toBe(true);
65+
});
66+
3167
it("stays hidden after its current warning is dismissed", () => {
3268
const status = warningProvider();
3369

‎apps/web/src/components/chat/ProviderStatusBanner.tsx‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,20 @@ import { formatProviderDriverKindLabel } from "../../providerModels";
77
import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip";
88

99
export function getProviderStatusBannerKey(status: ServerProvider | null): string | null {
10-
return !status || status.status === "ready" || status.status === "disabled"
11-
? null
12-
: [status.instanceId, status.status, status.auth.status, status.message ?? ""].join("\u0000");
10+
if (!status || status.status === "ready" || status.status === "disabled") return null;
11+
// Antigravity checks saved credentials when a session starts. Its local
12+
// health check leaves auth unknown after a restart, which is not a failure.
13+
if (
14+
status.driver === "antigravity" &&
15+
status.installed &&
16+
status.status === "warning" &&
17+
status.auth.status === "unknown"
18+
) {
19+
return null;
20+
}
21+
return [status.instanceId, status.status, status.auth.status, status.message ?? ""].join(
22+
"\u0000",
23+
);
1324
}
1425

1526
export function shouldShowProviderStatusBanner(
@@ -59,7 +70,7 @@ export const ProviderStatusBanner = memo(function ProviderStatusBanner({
5970
onOpenProviderSetup?: (instanceId: ProviderInstanceId) => void;
6071
status: ServerProvider | null;
6172
}) {
62-
if (!status || status.status === "ready" || status.status === "disabled") {
73+
if (!status || getProviderStatusBannerKey(status) === null) {
6374
return null;
6475
}
6576

‎docs/user/providers-antigravity.md‎

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,10 +179,14 @@ paid-plan tier or remaining subscription quota. See Google's [Antigravity plans]
179179
[personal Google sign-in guide][google-setup].
180180

181181
After an environment restarts, Google sign-in can show as not checked until an authenticated
182-
session succeeds. To check account access and reload models, use **Refresh provider status**
183-
in web or desktop provider settings, or **Refresh models** in the mobile model picker. Refresh
184-
uses saved Google sign-in and does not open a login page. If sign-in is required, use the
185-
provider's setup controls. Automatic status checks verify the installation only.
182+
session succeeds. You can continue an existing thread. Antigravity checks saved Google sign-in
183+
when the session starts. An unchecked status does not require signing in again.
184+
185+
To check account access and reload models on web or desktop, open **Settings** > **Providers**
186+
and select the circular arrow beside **Checked** at the top of the page. Its tooltip says
187+
**Refresh provider status**. On mobile, use **Refresh models** in the model picker.
188+
Refresh uses saved Google sign-in and does not open a login page. If sign-in is required,
189+
use the provider's setup controls. Automatic status checks verify the installation only.
186190

187191
The packaged runtime can be slow to start, especially on Windows. Health checks, model refresh,
188192
and sign-out each allow up to 90 seconds before reporting a timeout.

0 commit comments

Comments
 (0)