Skip to content

Commit afd6a9b

Browse files
committed
fix(vscode): stop walling API-key providers behind the sign-in screen
The init status reported not-logged-in whenever the login check was false, even with models configured. That check is true only for a Pythinker account or a provider OAuth token, so a provider authenticated by a plain API key in config.toml never satisfied it and the sign-in screen returned on every reload -- the skip is component state, so it never persisted. A configured model is what makes the extension usable, so it now decides ready on its own. The status derivation moves into a pure resolveInitStatus so the three branches collapse into one rule and can be tested directly.
1 parent b7eeafe commit afd6a9b

3 files changed

Lines changed: 48 additions & 17 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@pymodel/pythinker-code": patch
3+
---
4+
5+
Fix the VS Code extension opening on the sign-in screen for providers authenticated with a plain API key: a configured model now opens straight into the chat.

apps/vscode/test/app-init.test.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ vi.mock("@/components/ui/sonner", () => ({
1818
toast: { error: vi.fn(), warning: vi.fn() },
1919
}));
2020

21-
import { resolveAppView, type AppStatus } from "../webview-ui/src/hooks/useAppInit";
21+
import { resolveAppView, resolveInitStatus, type AppStatus } from "../webview-ui/src/hooks/useAppInit";
2222

2323
function resolve(
2424
status: AppStatus,
@@ -84,3 +84,24 @@ describe("resolveAppView", () => {
8484
}
8585
});
8686
});
87+
88+
describe("resolveInitStatus", () => {
89+
it("is ready with configured models even when nothing reports a login", () => {
90+
// Regression: an API-key-only provider satisfies neither `isAuthenticated()`
91+
// nor a provider OAuth token, so this state walled a fully configured user
92+
// behind a sign-in screen on every reload.
93+
expect(resolveInitStatus({ modelsCount: 2, loggedIn: false })).toBe("ready");
94+
});
95+
96+
it("is ready with configured models when a login is reported", () => {
97+
expect(resolveInitStatus({ modelsCount: 2, loggedIn: true })).toBe("ready");
98+
});
99+
100+
it("asks for setup when a login exists but no model is configured", () => {
101+
expect(resolveInitStatus({ modelsCount: 0, loggedIn: true })).toBe("no-models");
102+
});
103+
104+
it("asks a brand-new user to add a provider", () => {
105+
expect(resolveInitStatus({ modelsCount: 0, loggedIn: false })).toBe("not-logged-in");
106+
});
107+
});

apps/vscode/webview-ui/src/hooks/useAppInit.ts

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,22 @@ export type AppViewResolution =
1717
}
1818
| { readonly view: "main" };
1919

20+
/**
21+
* Pure status router for init. A configured model is what makes the extension
22+
* usable, so it decides `ready` on its own: `loggedIn` covers a Pythinker
23+
* account or a provider OAuth token, and a provider authenticated by a plain
24+
* API key in `config.toml` has neither. Gating on it walled off every
25+
* API-key-only user behind a sign-in screen they could not satisfy and had to
26+
* dismiss on each reload, because the skip is component state.
27+
*/
28+
export function resolveInitStatus(input: {
29+
readonly modelsCount: number;
30+
readonly loggedIn: boolean;
31+
}): AppStatus {
32+
if (input.modelsCount > 0) return "ready";
33+
return input.loggedIn ? "no-models" : "not-logged-in";
34+
}
35+
2036
/**
2137
* Pure view router for App. The `no-models` status (a managed OAuth token
2238
* exists but config.toml has no models — e.g. a first login whose model
@@ -111,22 +127,11 @@ export function useAppInit(): AppInitState {
111127

112128
const modelsCount = modelsConfig.models?.length ?? 0;
113129

114-
if (modelsCount === 0 && !loginStatus.loggedIn) {
115-
setState({ status: "not-logged-in", errorMessage: null, modelsCount });
116-
return;
117-
}
118-
119-
if (modelsCount === 0) {
120-
setState({ status: "no-models", errorMessage: null, modelsCount: 0 });
121-
return;
122-
}
123-
124-
if (!loginStatus.loggedIn) {
125-
setState({ status: "not-logged-in", errorMessage: null, modelsCount });
126-
return;
127-
}
128-
129-
setState({ status: "ready", errorMessage: null, modelsCount });
130+
setState({
131+
status: resolveInitStatus({ modelsCount, loggedIn: loginStatus.loggedIn }),
132+
errorMessage: null,
133+
modelsCount,
134+
});
130135
} catch (error) {
131136
if (!cancelled) {
132137
setState({

0 commit comments

Comments
 (0)