mirror of
https://github.com/openclaw/openclaw.git
synced 2026-07-21 10:16:44 +00:00
fix(onboarding): explain how to get provider tokens and revive logged-out CLI candidates (#108739)
* fix(onboarding): explain how to obtain provider tokens in auth setup copy * fix(onboarding): add per-CLI login remediation to detected candidate details
This commit is contained in:
@@ -121,7 +121,7 @@ OpenClaw's interactive login flows are implemented in `openclaw/plugin-sdk/llm.t
|
||||
|
||||
Flow shape:
|
||||
|
||||
1. start Anthropic setup-token or paste-token from OpenClaw
|
||||
1. create the token by running `claude setup-token` on any machine with Claude Code, then start Anthropic setup-token or paste-token from OpenClaw
|
||||
2. OpenClaw stores the resulting Anthropic credential in an auth profile
|
||||
3. model selection stays on `anthropic/...`
|
||||
4. existing Anthropic auth profiles remain available for rollback/order control
|
||||
|
||||
@@ -127,6 +127,18 @@ OpenClaw release:
|
||||
[OpenAI Codex](/providers/openai).
|
||||
</Warning>
|
||||
|
||||
### Get a setup token
|
||||
|
||||
Run `claude setup-token` on any machine with Claude Code installed. It prints
|
||||
a long-lived token starting with `sk-ant-oat01-`.
|
||||
|
||||
During onboarding, paste the token in the macOS app by choosing
|
||||
**Anthropic setup-token** under **Connect with an API key or token**, or use:
|
||||
|
||||
```bash
|
||||
openclaw models auth login --provider anthropic --method setup-token
|
||||
```
|
||||
|
||||
### Config example
|
||||
|
||||
Prefer the canonical Anthropic model ref plus a CLI runtime override:
|
||||
|
||||
@@ -22,6 +22,9 @@ Choose your preferred auth method and follow the setup steps.
|
||||
**Best for:** standard Gemini API access through Google AI Studio.
|
||||
|
||||
<Steps>
|
||||
<Step title="Get an API key">
|
||||
Create a free key in [Google AI Studio](https://aistudio.google.com/apikey).
|
||||
</Step>
|
||||
<Step title="Run onboarding">
|
||||
```bash
|
||||
openclaw onboard --auth-choice gemini-api-key
|
||||
@@ -61,7 +64,7 @@ Choose your preferred auth method and follow the setup steps.
|
||||
</Tab>
|
||||
|
||||
<Tab title="Gemini CLI (OAuth)">
|
||||
**Best for:** reusing an existing Gemini CLI login via PKCE OAuth instead of a separate API key.
|
||||
**Best for:** signing in with your Google account through Gemini CLI OAuth instead of using a separate API key.
|
||||
|
||||
<Warning>
|
||||
The `google-gemini-cli` provider is an unofficial integration. Some users
|
||||
@@ -116,6 +119,10 @@ Choose your preferred auth method and follow the setup steps.
|
||||
command is installed and on `PATH`.
|
||||
</Note>
|
||||
|
||||
Onboarding auto-detection lists an existing Gemini CLI login but never
|
||||
auto-tests it because Gemini CLI has no tool-free probe. Choose Gemini CLI
|
||||
OAuth or a Gemini API key to continue.
|
||||
|
||||
`google-gemini-cli/*` model refs are legacy compatibility aliases. New
|
||||
configs should use `google/*` model refs plus the `google-gemini-cli`
|
||||
runtime when they want local Gemini CLI execution.
|
||||
|
||||
@@ -80,6 +80,11 @@ and shows why the previous one failed. If several options are found you can
|
||||
switch between them before continuing. Automatic local discovery never pulls
|
||||
or downloads a model.
|
||||
|
||||
To use a Claude subscription when the Gateway host has no Claude CLI login, run
|
||||
`claude setup-token` on any machine with Claude Code installed, then paste the
|
||||
printed token as **Anthropic setup-token** under **Connect with an API key or
|
||||
token**.
|
||||
|
||||
Gemini CLI and Antigravity remain available for normal use after setup. Their
|
||||
installed CLIs are shown for context but are not auto-tested because neither can
|
||||
enforce the tool-free inference probe.
|
||||
|
||||
@@ -262,7 +262,7 @@
|
||||
"choiceId": "anthropic-cli",
|
||||
"deprecatedChoiceIds": ["claude-cli"],
|
||||
"choiceLabel": "Anthropic Claude CLI",
|
||||
"choiceHint": "Reuse a local Claude CLI login on this host",
|
||||
"choiceHint": "Keep using an existing Claude Code CLI login on this host",
|
||||
"assistantPriority": -20,
|
||||
"groupId": "anthropic",
|
||||
"groupLabel": "Anthropic",
|
||||
@@ -275,7 +275,7 @@
|
||||
"choiceId": "setup-token",
|
||||
"appGuidedSecret": true,
|
||||
"choiceLabel": "Anthropic setup-token",
|
||||
"choiceHint": "Manual token path",
|
||||
"choiceHint": "Token created by running 'claude setup-token' in your terminal",
|
||||
"assistantPriority": 40,
|
||||
"groupId": "anthropic",
|
||||
"groupLabel": "Anthropic",
|
||||
|
||||
@@ -19,12 +19,12 @@ export function createAnthropicProvider(): ProviderPlugin {
|
||||
id: "cli",
|
||||
kind: "custom",
|
||||
label: "Claude CLI",
|
||||
hint: "Reuse a local Claude CLI login and switch model selection to claude-cli/*",
|
||||
hint: "Keep using a local Claude CLI login and run Anthropic models through the Claude CLI runtime",
|
||||
run: noopAuth,
|
||||
wizard: {
|
||||
choiceId: "anthropic-cli",
|
||||
choiceLabel: "Anthropic Claude CLI",
|
||||
choiceHint: "Reuse a local Claude CLI login on this host",
|
||||
choiceHint: "Keep using an existing Claude Code CLI login on this host",
|
||||
groupId: "anthropic",
|
||||
groupLabel: "Anthropic",
|
||||
groupHint: "Claude CLI + API key",
|
||||
@@ -34,12 +34,12 @@ export function createAnthropicProvider(): ProviderPlugin {
|
||||
id: "setup-token",
|
||||
kind: "token",
|
||||
label: "Anthropic setup-token",
|
||||
hint: "Manual bearer token path",
|
||||
hint: "Paste a long-lived token created with 'claude setup-token'",
|
||||
run: noopAuth,
|
||||
wizard: {
|
||||
choiceId: "setup-token",
|
||||
choiceLabel: "Anthropic setup-token",
|
||||
choiceHint: "Manual token path",
|
||||
choiceHint: "Token created by running 'claude setup-token' in your terminal",
|
||||
groupId: "anthropic",
|
||||
groupLabel: "Anthropic",
|
||||
groupHint: "Claude CLI + API key + token",
|
||||
|
||||
@@ -810,12 +810,12 @@ export function buildAnthropicProvider(): ProviderPlugin {
|
||||
{
|
||||
id: "cli",
|
||||
label: "Claude CLI",
|
||||
hint: "Reuse a local Claude CLI login and run Anthropic models through the Claude CLI runtime",
|
||||
hint: "Keep using a local Claude CLI login and run Anthropic models through the Claude CLI runtime",
|
||||
kind: "custom",
|
||||
wizard: {
|
||||
choiceId: "anthropic-cli",
|
||||
choiceLabel: "Anthropic Claude CLI",
|
||||
choiceHint: "Reuse a local Claude CLI login on this host",
|
||||
choiceHint: "Keep using an existing Claude Code CLI login on this host",
|
||||
assistantPriority: -20,
|
||||
groupId: "anthropic",
|
||||
groupLabel: "Anthropic",
|
||||
@@ -837,12 +837,12 @@ export function buildAnthropicProvider(): ProviderPlugin {
|
||||
{
|
||||
id: "setup-token",
|
||||
label: "Anthropic setup-token",
|
||||
hint: "Manual bearer token path",
|
||||
hint: "Paste a long-lived token created with 'claude setup-token'",
|
||||
kind: "token",
|
||||
wizard: {
|
||||
choiceId: "setup-token",
|
||||
choiceLabel: "Anthropic setup-token",
|
||||
choiceHint: "Manual token path",
|
||||
choiceHint: "Token created by running 'claude setup-token' in your terminal",
|
||||
assistantPriority: 40,
|
||||
groupId: "anthropic",
|
||||
groupLabel: "Anthropic",
|
||||
|
||||
@@ -115,7 +115,7 @@ export function buildGoogleGeminiCliProvider(): ProviderPlugin {
|
||||
setup: {
|
||||
choiceId: "google-gemini-cli",
|
||||
choiceLabel: "Gemini CLI OAuth",
|
||||
choiceHint: "Google OAuth with project-aware token payload",
|
||||
choiceHint: "Sign in with your Google account (opens a browser)",
|
||||
methodId: "oauth",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -630,6 +630,7 @@
|
||||
"choiceId": "gemini-api-key",
|
||||
"appGuidedSecret": true,
|
||||
"choiceLabel": "Google Gemini API key",
|
||||
"choiceHint": "Free API key from aistudio.google.com/apikey",
|
||||
"groupId": "google",
|
||||
"groupLabel": "Google",
|
||||
"groupHint": "Gemini API key + OAuth",
|
||||
@@ -645,7 +646,7 @@
|
||||
"choiceId": "google-gemini-cli",
|
||||
"appGuidedAuth": "oauth",
|
||||
"choiceLabel": "Gemini CLI OAuth",
|
||||
"choiceHint": "Google OAuth with project-aware token payload",
|
||||
"choiceHint": "Sign in with your Google account (opens a browser)",
|
||||
"groupId": "google",
|
||||
"groupLabel": "Google",
|
||||
"groupHint": "Gemini API key + OAuth",
|
||||
|
||||
@@ -15,7 +15,7 @@ export function createGoogleProvider(): ProviderPlugin {
|
||||
id: "api-key",
|
||||
kind: "api_key",
|
||||
label: "Google Gemini API key",
|
||||
hint: "AI Studio / Gemini API key",
|
||||
hint: "Free API key from aistudio.google.com/apikey",
|
||||
run: noopAuth,
|
||||
wizard: {
|
||||
choiceId: "gemini-api-key",
|
||||
@@ -70,7 +70,7 @@ export function createGoogleGeminiCliProvider(): ProviderPlugin {
|
||||
setup: {
|
||||
choiceId: "google-gemini-cli",
|
||||
choiceLabel: "Gemini CLI OAuth",
|
||||
choiceHint: "Google OAuth with project-aware token payload",
|
||||
choiceHint: "Sign in with your Google account (opens a browser)",
|
||||
methodId: "oauth",
|
||||
},
|
||||
},
|
||||
|
||||
@@ -48,7 +48,7 @@ export function buildGoogleProvider(): ProviderPlugin {
|
||||
providerId: "google",
|
||||
methodId: "api-key",
|
||||
label: "Google Gemini API key",
|
||||
hint: "AI Studio / Gemini API key",
|
||||
hint: "Free API key from aistudio.google.com/apikey",
|
||||
optionKey: "geminiApiKey",
|
||||
flagName: "--gemini-api-key",
|
||||
envVar: "GEMINI_API_KEY",
|
||||
|
||||
@@ -389,7 +389,7 @@
|
||||
"method": "app-server",
|
||||
"choiceId": "codex",
|
||||
"choiceLabel": "Codex app-server",
|
||||
"choiceHint": "Use the Codex app-server runtime and managed model catalog.",
|
||||
"choiceHint": "Keep using your Codex CLI or ChatGPT app sign-in via the Codex app-server runtime.",
|
||||
"assistantPriority": -40,
|
||||
"groupId": "codex",
|
||||
"groupLabel": "Codex",
|
||||
|
||||
@@ -131,7 +131,37 @@ describe("detectInferenceBackends", () => {
|
||||
expect(candidates.map((candidate) => candidate.kind)).toEqual(["codex-cli", "claude-cli"]);
|
||||
expect(candidates[0]?.credentials).toBe(true);
|
||||
expect(candidates[1]?.credentials).toBe(false);
|
||||
expect(candidates[1]?.detail).toBe("installed, not logged in");
|
||||
expect(candidates[1]?.detail).toBe(
|
||||
"installed, not logged in — run `claude auth login`, then check again",
|
||||
);
|
||||
});
|
||||
|
||||
it("gives each logged-out CLI its sign-in remediation", async () => {
|
||||
const candidates = await detectInferenceBackends({
|
||||
env: {},
|
||||
platform: "linux",
|
||||
deps: {
|
||||
probeLocalCommand: probeDeps({ claude: true, codex: true, gemini: true }),
|
||||
readClaudeCliCredentials: () => null,
|
||||
readCodexCliCredentials: () => null,
|
||||
readGeminiCliCredentials: () => null,
|
||||
},
|
||||
});
|
||||
|
||||
expect(candidates).toMatchObject([
|
||||
{
|
||||
kind: "claude-cli",
|
||||
detail: "installed, not logged in — run `claude auth login`, then check again",
|
||||
},
|
||||
{
|
||||
kind: "codex-cli",
|
||||
detail: "installed, not logged in — run `codex login`, then check again",
|
||||
},
|
||||
{
|
||||
kind: "gemini-cli",
|
||||
detail: "installed, not logged in — sign in to Gemini CLI, then check again",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("recognizes Codex login status across native credential stores", async () => {
|
||||
|
||||
@@ -85,12 +85,12 @@ function detectCliCredentialState(params: {
|
||||
return params.platform === "darwin" ? undefined : false;
|
||||
}
|
||||
|
||||
function describeCliDetail(credentials: boolean | undefined): string {
|
||||
function describeCliDetail(credentials: boolean | undefined, loginHint: string): string {
|
||||
if (credentials === true) {
|
||||
return "logged in";
|
||||
}
|
||||
if (credentials === false) {
|
||||
return "installed, not logged in";
|
||||
return `installed, not logged in — ${loginHint}, then check again`;
|
||||
}
|
||||
return "installed";
|
||||
}
|
||||
@@ -247,7 +247,7 @@ export async function detectInferenceBackends(
|
||||
kind: "claude-cli",
|
||||
modelRef: CLAUDE_CLI_DEFAULT_MODEL_REF,
|
||||
label: "Claude Code",
|
||||
detail: describeCliDetail(credentials),
|
||||
detail: describeCliDetail(credentials, "run `claude auth login`"),
|
||||
...(credentials === undefined ? {} : { credentials }),
|
||||
});
|
||||
}
|
||||
@@ -263,7 +263,7 @@ export async function detectInferenceBackends(
|
||||
kind: "codex-cli",
|
||||
modelRef: CODEX_APP_SERVER_DEFAULT_MODEL_REF,
|
||||
label: "Codex",
|
||||
detail: describeCliDetail(credentials),
|
||||
detail: describeCliDetail(credentials, "run `codex login`"),
|
||||
...(credentials === undefined ? {} : { credentials }),
|
||||
});
|
||||
}
|
||||
@@ -275,7 +275,7 @@ export async function detectInferenceBackends(
|
||||
kind: "gemini-cli",
|
||||
modelRef: GEMINI_CLI_DEFAULT_MODEL_REF,
|
||||
label: "Gemini CLI",
|
||||
detail: describeCliDetail(credentials),
|
||||
detail: describeCliDetail(credentials, "sign in to Gemini CLI"),
|
||||
credentials,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -101,7 +101,7 @@ vi.mock("../commands/onboard-inference.js", async (importActual) => {
|
||||
kind: "codex-cli",
|
||||
modelRef: "openai/gpt-5.5",
|
||||
label: "Codex",
|
||||
detail: "installed, not logged in",
|
||||
detail: "installed, not logged in — run `codex login`, then check again",
|
||||
credentials: false,
|
||||
},
|
||||
]),
|
||||
|
||||
@@ -362,7 +362,8 @@ export async function detectSetupInference(
|
||||
id: candidate.kind,
|
||||
label: candidate.label,
|
||||
detail: candidate.detail,
|
||||
reason: "Automatic setup cannot enforce a tool-free Gemini CLI probe.",
|
||||
reason:
|
||||
"Can't be auto-tested safely here. Use 'Gemini CLI OAuth' or a Gemini API key instead.",
|
||||
}));
|
||||
const antigravity = await (deps.probeLocalCommand ?? probeLocalCommand)("agy");
|
||||
if (antigravity.found) {
|
||||
@@ -370,7 +371,8 @@ export async function detectSetupInference(
|
||||
id: "antigravity-cli",
|
||||
label: "Antigravity CLI",
|
||||
detail: "installed",
|
||||
reason: "Automatic setup cannot enforce a tool-free Antigravity probe.",
|
||||
reason:
|
||||
"Can't be auto-tested safely here. Sign in with a provider or use an API key instead.",
|
||||
});
|
||||
}
|
||||
const raw = detected.filter((candidate) => candidate.kind !== "gemini-cli");
|
||||
|
||||
Reference in New Issue
Block a user