fix: prefer Claude CLI in Anthropic onboarding

This commit is contained in:
Peter Steinberger
2026-04-04 14:49:42 +09:00
parent 1ab37d7a12
commit ae7942bf5e
22 changed files with 199 additions and 47 deletions

View File

@@ -3,7 +3,7 @@ summary: "OAuth in OpenClaw: token exchange, storage, and multi-account patterns
read_when:
- You want to understand OpenClaw OAuth end-to-end
- You hit token invalidation / logout issues
- You want setup-token or OAuth auth flows
- You want setup-token, Claude CLI, or OAuth auth flows
- You want multiple accounts or profile routing
title: "OAuth"
---
@@ -153,10 +153,14 @@ Claude CLI path:
3. store no new auth profile; switch model selection to `claude-cli/...`
4. keep existing Anthropic auth profiles for rollback
Wizard paths:
Interactive assistant path:
- `openclaw onboard` → auth choice `anthropic-cli`
- `openclaw onboard` → auth choice `setup-token` (Anthropic)
- `openclaw onboard` / `openclaw configure` → auth choice `anthropic-cli`
Manual setup-token path:
- `openclaw models auth setup-token --provider anthropic`
- `openclaw models auth paste-token --provider anthropic`
### OpenAI Codex (ChatGPT OAuth)

View File

@@ -158,6 +158,10 @@ Onboarding shortcut:
openclaw onboard --auth-choice anthropic-cli
```
Interactive `openclaw onboard` and `openclaw configure` prefer Claude CLI for
Anthropic and do not show setup-token in the assistant picker. Setup-token
remains supported through the manual commands above.
## Checking model auth status
```bash

View File

@@ -590,7 +590,7 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
</Accordion>
<Accordion title="How does Anthropic setup-token auth work?">
`claude setup-token` generates a **token string** via the Claude Code CLI (it is not available in the web console). You can run it on **any machine**. Choose **Anthropic token (paste setup-token)** in onboarding or paste it with `openclaw models auth paste-token --provider anthropic`. The token is stored as an auth profile for the **anthropic** provider and used like an API key (no auto-refresh). More detail: [OAuth](/concepts/oauth).
`claude setup-token` generates a **token string** via the Claude Code CLI (it is not available in the web console). You can run it on **any machine**. Interactive onboarding/configure no longer shows setup-token as an assistant choice; use `openclaw models auth setup-token --provider anthropic` or paste an existing token with `openclaw models auth paste-token --provider anthropic`. The token is stored as an auth profile for the **anthropic** provider and used like an API key (no auto-refresh). More detail: [OAuth](/concepts/oauth).
</Accordion>
<Accordion title="Where do I find an Anthropic setup-token?">
@@ -600,17 +600,17 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
claude setup-token
```
Copy the token it prints, then choose **Anthropic token (paste setup-token)** in onboarding. If you want to run it on the gateway host, use `openclaw models auth setup-token --provider anthropic`. If you ran `claude setup-token` elsewhere, paste it on the gateway host with `openclaw models auth paste-token --provider anthropic`. See [Anthropic](/providers/anthropic).
Copy the token it prints, then either run `openclaw models auth setup-token --provider anthropic` on the gateway host or paste it there with `openclaw models auth paste-token --provider anthropic`. See [Anthropic](/providers/anthropic).
</Accordion>
<Accordion title="Do you support Claude subscription auth (Claude Pro or Max)?">
Yes. You can either:
- use a **setup-token**
- reuse a local **Claude CLI** login on the gateway host with `openclaw models auth login --provider anthropic --method cli --set-default`
- use a **setup-token** manually with `openclaw models auth setup-token --provider anthropic`
Setup-token is still supported. Claude CLI migration is simpler when the gateway host already runs Claude Code. See [Anthropic](/providers/anthropic) and [OAuth](/concepts/oauth).
Claude CLI is the preferred interactive Anthropic path. Setup-token is still supported for manual config. See [Anthropic](/providers/anthropic) and [OAuth](/concepts/oauth).
Important: Anthropic changed third-party harness billing on **April 4, 2026
at 12:00 PM PT / 8:00 PM BST**. Anthropic says Claude subscription limits no

View File

@@ -305,6 +305,11 @@ Or in onboarding:
openclaw onboard --auth-choice anthropic-cli
```
Interactive `openclaw onboard` and `openclaw configure` now prefer **Anthropic
Claude CLI** first and **Anthropic API key** second. The setup-token flow
remains supported through manual auth commands, but is not shown in the
assistant picker.
What this does:
- verifies Claude CLI is already signed in on the gateway host
@@ -339,7 +344,7 @@ you need to.
More details: [/gateway/cli-backends](/gateway/cli-backends)
## Option C: Claude setup-token
## Option C: Claude setup-token (manual)
**Best for:** using your Claude subscription with Anthropic **Extra Usage**
enabled, or while transitioning to API-key billing.
@@ -352,25 +357,18 @@ Setup-tokens are created by the **Claude Code CLI**, not the Anthropic Console.
claude setup-token
```
Paste the token into OpenClaw (wizard: **Anthropic token (paste setup-token)**), or run it on the gateway host:
Then either run it on the gateway host:
```bash
openclaw models auth setup-token --provider anthropic
```
If you generated the token on a different machine, paste it:
Or if you generated the token on a different machine, paste it:
```bash
openclaw models auth paste-token --provider anthropic
```
### CLI setup (setup-token)
```bash
# Paste a setup-token during setup
openclaw onboard --auth-choice setup-token
```
### Config snippet (setup-token)
```json5

View File

@@ -31,8 +31,8 @@ For a high-level overview, see [Onboarding (CLI)](/start/wizard).
</Step>
<Step title="Model/Auth">
- **Anthropic API key**: uses `ANTHROPIC_API_KEY` if present or prompts for a key, then saves it for daemon use.
- **Anthropic Claude CLI**: on macOS onboarding checks Keychain item "Claude Code-credentials" (choose "Always Allow" so launchd starts don't block); on Linux/Windows it reuses `~/.claude/.credentials.json` if present and switches model selection to `claude-cli/...`.
- **Anthropic token (paste setup-token)**: run `claude setup-token` on any machine, then paste the token (you can name it; blank = default).
- **Anthropic Claude CLI**: preferred Anthropic assistant choice in onboarding/configure. On macOS onboarding checks Keychain item "Claude Code-credentials" (choose "Always Allow" so launchd starts don't block); on Linux/Windows it reuses `~/.claude/.credentials.json` if present and switches model selection to `claude-cli/...`.
- **Anthropic setup-token**: still supported as a manual auth flow with `openclaw models auth setup-token --provider anthropic` or `openclaw models auth paste-token --provider anthropic`, but no longer shown in the interactive assistant picker.
- **OpenAI Code (Codex) subscription (Codex CLI)**: if `~/.codex/auth.json` exists, onboarding can reuse it. Reused Codex CLI credentials stay managed by Codex CLI; OpenClaw re-reads that source on expiry instead of rotating the copied refresh token itself.
- **OpenAI Code (Codex) subscription (OAuth)**: browser flow; paste the `code#state`.
- Sets `agents.defaults.model` to `openai-codex/gpt-5.2` when model is unset or `openai/*`.

View File

@@ -51,6 +51,19 @@ openclaw onboard --non-interactive \
## Provider-specific examples
<AccordionGroup>
<Accordion title="Anthropic Claude CLI example">
```bash
openclaw onboard --non-interactive \
--mode local \
--auth-choice anthropic-cli \
--gateway-port 18789 \
--gateway-bind loopback
```
Requires Claude CLI already installed and signed in on the same gateway
host.
</Accordion>
<Accordion title="Gemini example">
```bash
openclaw onboard --non-interactive \
@@ -182,6 +195,11 @@ openclaw onboard --non-interactive \
</Accordion>
</AccordionGroup>
Anthropic setup-token remains supported for manual flows, but interactive
onboarding/configure no longer offers it as an assistant choice. Use
`openclaw models auth setup-token --provider anthropic` or
`openclaw models auth paste-token --provider anthropic` when you need it.
## Add another agent
Use `openclaw agents add <name>` to create a separate agent with its own workspace,

View File

@@ -16,7 +16,7 @@ For the short guide, see [Onboarding (CLI)](/start/wizard).
Local mode (default) walks you through:
- Model and auth setup (OpenAI Code subscription OAuth, Anthropic API key or setup token, plus MiniMax, GLM, Ollama, Moonshot, StepFun, and AI Gateway options)
- Model and auth setup (OpenAI Code subscription OAuth, Anthropic Claude CLI or API key, plus MiniMax, GLM, Ollama, Moonshot, StepFun, and AI Gateway options)
- Workspace location and bootstrap files
- Gateway settings (port, bind, auth, tailscale)
- Channels and providers (Telegram, WhatsApp, Discord, Google Chat, Mattermost plugin, Signal)
@@ -130,15 +130,22 @@ What you set:
Reuses a local Claude CLI login on the gateway host and switches model
selection to `claude-cli/...`.
This is the preferred interactive Anthropic path in `openclaw onboard` and
`openclaw configure`.
- macOS: checks Keychain item "Claude Code-credentials"
- Linux and Windows: reuses `~/.claude/.credentials.json` if present
On macOS, choose "Always Allow" so launchd starts do not block.
</Accordion>
<Accordion title="Anthropic token (setup-token paste)">
Run `claude setup-token` on any machine, then paste the token.
You can name it; blank uses default.
<Accordion title="Anthropic setup-token (manual)">
Supported for manual config, not shown as an interactive assistant choice.
- Generate on any machine: `claude setup-token`
- Run on the gateway host: `openclaw models auth setup-token --provider anthropic`
- Or paste an existing token: `openclaw models auth paste-token --provider anthropic`
</Accordion>
<Accordion title="OpenAI Code subscription (Codex CLI reuse)">
If `~/.codex/auth.json` exists, the wizard can reuse it.

View File

@@ -66,12 +66,13 @@ Onboarding starts with **QuickStart** (defaults) vs **Advanced** (full control).
**Local mode (default)** walks you through these steps:
1. **Model/Auth** — choose any supported provider/auth flow (API key, OAuth, or setup-token), including Custom Provider
1. **Model/Auth** — choose any supported provider/auth flow (API key, OAuth, or provider-specific manual auth), including Custom Provider
(OpenAI-compatible, Anthropic-compatible, or Unknown auto-detect). Pick a default model.
Security note: if this agent will run tools or process webhook/hooks content, prefer the strongest latest-generation model available and keep tool policy strict. Weaker/older tiers are easier to prompt-inject.
For non-interactive runs, `--secret-input-mode ref` stores env-backed refs in auth profiles instead of plaintext API key values.
In non-interactive `ref` mode, the provider env var must be set; passing inline key flags without that env var fails fast.
In interactive runs, choosing secret reference mode lets you point at either an environment variable or a configured provider ref (`file` or `exec`), with a fast preflight validation before saving.
For Anthropic, interactive onboarding/configure prefers **Anthropic Claude CLI** first, then **Anthropic API key**. The **setup-token** flow remains supported through manual auth commands.
2. **Workspace** — Location for agent files (default `~/.openclaw/workspace`). Seeds bootstrap files.
3. **Gateway** — Port, bind address, auth mode, Tailscale exposure.
In interactive token mode, choose default plaintext token storage or opt into SecretRef.

View File

@@ -382,6 +382,7 @@ export default definePluginEntry({
choiceId: "anthropic-cli",
choiceLabel: "Anthropic Claude CLI",
choiceHint: "Reuse a local Claude CLI login on this host",
assistantPriority: -20,
groupId: "anthropic",
groupLabel: "Anthropic",
groupHint: "Claude CLI + setup-token + API key",
@@ -409,6 +410,7 @@ export default definePluginEntry({
choiceId: "token",
choiceLabel: "Anthropic token (paste setup-token)",
choiceHint: "Run `claude setup-token` elsewhere, then paste the token here",
assistantVisibility: "manual-only",
groupId: "anthropic",
groupLabel: "Anthropic",
groupHint: "Claude CLI + setup-token + API key",

View File

@@ -17,6 +17,7 @@
"deprecatedChoiceIds": ["claude-cli"],
"choiceLabel": "Anthropic Claude CLI",
"choiceHint": "Reuse a local Claude CLI login on this host",
"assistantPriority": -20,
"groupId": "anthropic",
"groupLabel": "Anthropic",
"groupHint": "Claude CLI + setup-token + API key"
@@ -27,6 +28,7 @@
"choiceId": "token",
"choiceLabel": "Anthropic token (paste setup-token)",
"choiceHint": "Run `claude setup-token` elsewhere, then paste the token here",
"assistantVisibility": "manual-only",
"groupId": "anthropic",
"groupLabel": "Anthropic",
"groupHint": "Claude CLI + setup-token + API key"

View File

@@ -1,5 +1,5 @@
import { resolveLegacyAuthChoiceAliasesForCli } from "./auth-choice-legacy.js";
import type { AuthChoice, AuthChoiceGroupId } from "./onboard-types.js";
import { resolveLegacyAuthChoiceAliasesForCli } from "./auth-choice-legacy.js";
export type { AuthChoiceGroupId };
@@ -10,6 +10,8 @@ export type AuthChoiceOption = {
groupId?: AuthChoiceGroupId;
groupLabel?: string;
groupHint?: string;
assistantPriority?: number;
assistantVisibility?: "visible" | "manual-only";
};
export type AuthChoiceGroup = {

View File

@@ -378,6 +378,51 @@ describe("buildAuthChoiceOptions", () => {
expect(litellmGroup?.options.some((opt) => opt.value === "litellm-api-key")).toBe(true);
});
it("prefers Anthropic Claude CLI over API key and hides manual-only setup-token in grouped selection", () => {
resolveManifestProviderAuthChoices.mockReturnValue([
{
pluginId: "anthropic",
providerId: "anthropic",
methodId: "api-key",
choiceId: "apiKey",
choiceLabel: "Anthropic API key",
groupId: "anthropic",
groupLabel: "Anthropic",
},
{
pluginId: "anthropic",
providerId: "anthropic",
methodId: "cli",
choiceId: "anthropic-cli",
choiceLabel: "Anthropic Claude CLI",
assistantPriority: -20,
groupId: "anthropic",
groupLabel: "Anthropic",
},
{
pluginId: "anthropic",
providerId: "anthropic",
methodId: "setup-token",
choiceId: "token",
choiceLabel: "Anthropic token (paste setup-token)",
assistantVisibility: "manual-only",
groupId: "anthropic",
groupLabel: "Anthropic",
},
]);
const { groups } = buildAuthChoiceGroups({
store: EMPTY_STORE,
includeSkip: false,
});
const anthropicGroup = groups.find((group) => group.value === "anthropic");
expect(anthropicGroup).toBeDefined();
expect(anthropicGroup?.options.map((option) => option.value)).toEqual([
"anthropic-cli",
"apiKey",
]);
});
it("groups OpenCode Zen and Go under one OpenCode entry", () => {
resolveManifestProviderAuthChoices.mockReturnValue([
{

View File

@@ -1,5 +1,6 @@
import type { AuthProfileStore } from "../agents/auth-profiles.js";
import type { OpenClawConfig } from "../config/config.js";
import type { AuthChoice, AuthChoiceGroupId } from "./onboard-types.js";
import {
resolveManifestProviderSetupFlowContributions,
resolveProviderSetupFlowContributions,
@@ -10,12 +11,17 @@ import {
type AuthChoiceOption,
formatStaticAuthChoiceChoicesForCli,
} from "./auth-choice-options.static.js";
import type { AuthChoice, AuthChoiceGroupId } from "./onboard-types.js";
function compareOptionLabels(a: AuthChoiceOption, b: AuthChoiceOption): number {
return a.label.localeCompare(b.label);
}
function compareAssistantOptions(a: AuthChoiceOption, b: AuthChoiceOption): number {
const priorityA = a.assistantPriority ?? 0;
const priorityB = b.assistantPriority ?? 0;
return priorityA - priorityB || compareOptionLabels(a, b);
}
function compareGroupLabels(a: AuthChoiceGroup, b: AuthChoiceGroup): number {
return a.label.localeCompare(b.label);
}
@@ -63,6 +69,7 @@ export function formatAuthChoiceChoicesForCli(params?: {
export function buildAuthChoiceOptions(params: {
store: AuthProfileStore;
includeSkip: boolean;
assistantVisibleOnly?: boolean;
config?: OpenClawConfig;
workspaceDir?: string;
env?: NodeJS.ProcessEnv;
@@ -80,9 +87,11 @@ export function buildAuthChoiceOptions(params: {
optionByValue.set(option.value, option);
}
const options: AuthChoiceOption[] = Array.from(optionByValue.values()).toSorted(
compareOptionLabels,
);
const options: AuthChoiceOption[] = Array.from(optionByValue.values())
.toSorted(compareOptionLabels)
.filter((option) =>
params.assistantVisibleOnly ? option.assistantVisibility !== "manual-only" : true,
);
if (params.includeSkip) {
options.push({ value: "skip", label: "Skip for now" });
@@ -104,6 +113,7 @@ export function buildAuthChoiceGroups(params: {
const options = buildAuthChoiceOptions({
...params,
includeSkip: false,
assistantVisibleOnly: true,
});
const groupsById = new Map<AuthChoiceGroupId, AuthChoiceGroup>();
@@ -126,7 +136,7 @@ export function buildAuthChoiceGroups(params: {
const groups = Array.from(groupsById.values())
.map((group) => ({
...group,
options: [...group.options].toSorted(compareOptionLabels),
options: [...group.options].toSorted(compareAssistantOptions),
}))
.toSorted(compareGroupLabels);

View File

@@ -1,12 +1,12 @@
import type { OpenClawConfig } from "../config/config.js";
import type { ProviderPlugin } from "../plugins/types.js";
import type { FlowContribution, FlowOption } from "./types.js";
import { resolveManifestProviderAuthChoices } from "../plugins/provider-auth-choices.js";
import {
resolveProviderModelPickerEntries,
resolveProviderWizardOptions,
} from "../plugins/provider-wizard.js";
import { resolvePluginProviders } from "../plugins/providers.runtime.js";
import type { ProviderPlugin } from "../plugins/types.js";
import type { FlowContribution, FlowOption } from "./types.js";
import { mergeFlowContributions, sortFlowContributionsByLabel } from "./types.js";
export type ProviderFlowScope = "text-inference" | "image-generation";
@@ -95,6 +95,10 @@ export function resolveManifestProviderSetupFlowContributions(params?: {
value: choice.choiceId,
label: choice.choiceLabel,
...(choice.choiceHint ? { hint: choice.choiceHint } : {}),
...(choice.assistantPriority !== undefined
? { assistantPriority: choice.assistantPriority }
: {}),
...(choice.assistantVisibility ? { assistantVisibility: choice.assistantVisibility } : {}),
...(choice.groupId && choice.groupLabel
? {
group: {
@@ -142,6 +146,10 @@ export function resolveRuntimeFallbackProviderSetupFlowContributions(params?: {
value: option.value,
label: option.label,
...(option.hint ? { hint: option.hint } : {}),
...(option.assistantPriority !== undefined
? { assistantPriority: option.assistantPriority }
: {}),
...(option.assistantVisibility ? { assistantVisibility: option.assistantVisibility } : {}),
group: {
id: option.groupId,
label: option.groupLabel,

View File

@@ -19,6 +19,8 @@ export type FlowOption<Value extends string = string> = {
hint?: string;
group?: FlowOptionGroup;
docs?: FlowDocsLink;
assistantPriority?: number;
assistantVisibility?: "visible" | "manual-only";
};
export type FlowContribution<Value extends string = string> = {

View File

@@ -2,11 +2,11 @@ import fs from "node:fs";
import path from "node:path";
import { afterEach, describe, expect, it, vi } from "vitest";
import type { PluginCandidate } from "./discovery.js";
import type { OpenClawPackageManifest } from "./manifest.js";
import {
clearPluginManifestRegistryCache,
loadPluginManifestRegistry,
} from "./manifest-registry.js";
import type { OpenClawPackageManifest } from "./manifest.js";
import { cleanupTrackedTempDirs, makeTrackedTempDir } from "./test-helpers/fs-fixtures.js";
vi.unmock("../version.js");
@@ -389,6 +389,8 @@ describe("loadPluginManifestRegistry", () => {
method: "api-key",
choiceId: "openai-api-key",
choiceLabel: "OpenAI API key",
assistantPriority: 10,
assistantVisibility: "visible",
},
],
configSchema: { type: "object" },
@@ -411,6 +413,8 @@ describe("loadPluginManifestRegistry", () => {
method: "api-key",
choiceId: "openai-api-key",
choiceLabel: "OpenAI API key",
assistantPriority: 10,
assistantVisibility: "visible",
},
]);
});

View File

@@ -1,11 +1,11 @@
import JSON5 from "json5";
import fs from "node:fs";
import path from "node:path";
import JSON5 from "json5";
import type { ChannelConfigRuntimeSchema } from "../channels/plugins/types.plugin.js";
import type { PluginConfigUiHint, PluginKind } from "./types.js";
import { MANIFEST_KEY } from "../compat/legacy-names.js";
import { matchBoundaryFileOpenFailure, openBoundaryFileSync } from "../infra/boundary-file-read.js";
import { isRecord } from "../utils.js";
import type { PluginConfigUiHint, PluginKind } from "./types.js";
export const PLUGIN_MANIFEST_FILENAME = "openclaw.plugin.json";
export const PLUGIN_MANIFEST_FILENAMES = [PLUGIN_MANIFEST_FILENAME] as const;
@@ -91,6 +91,10 @@ export type PluginManifestProviderAuthChoice = {
/** Optional user-facing choice label/hint for grouped onboarding UI. */
choiceLabel?: string;
choiceHint?: string;
/** Lower values sort earlier in interactive assistant pickers. */
assistantPriority?: number;
/** Keep the choice out of interactive assistant pickers while preserving manual CLI support. */
assistantVisibility?: "visible" | "manual-only";
/** Legacy choice ids that should point users at this replacement choice. */
deprecatedChoiceIds?: string[];
/** Optional grouping metadata for auth-choice pickers. */
@@ -202,6 +206,14 @@ function normalizeProviderAuthChoices(
}
const choiceLabel = typeof entry.choiceLabel === "string" ? entry.choiceLabel.trim() : "";
const choiceHint = typeof entry.choiceHint === "string" ? entry.choiceHint.trim() : "";
const assistantPriority =
typeof entry.assistantPriority === "number" && Number.isFinite(entry.assistantPriority)
? entry.assistantPriority
: undefined;
const assistantVisibility =
entry.assistantVisibility === "manual-only" || entry.assistantVisibility === "visible"
? entry.assistantVisibility
: undefined;
const deprecatedChoiceIds = normalizeStringList(entry.deprecatedChoiceIds);
const groupId = typeof entry.groupId === "string" ? entry.groupId.trim() : "";
const groupLabel = typeof entry.groupLabel === "string" ? entry.groupLabel.trim() : "";
@@ -221,6 +233,8 @@ function normalizeProviderAuthChoices(
choiceId,
...(choiceLabel ? { choiceLabel } : {}),
...(choiceHint ? { choiceHint } : {}),
...(assistantPriority !== undefined ? { assistantPriority } : {}),
...(assistantVisibility ? { assistantVisibility } : {}),
...(deprecatedChoiceIds.length > 0 ? { deprecatedChoiceIds } : {}),
...(groupId ? { groupId } : {}),
...(groupLabel ? { groupLabel } : {}),
@@ -320,7 +334,7 @@ export function loadPluginManifest(
}
let raw: unknown;
try {
raw = JSON5.parse(fs.readFileSync(opened.fd, "utf-8")) as unknown;
raw = JSON5.parse(fs.readFileSync(opened.fd, "utf-8"));
} catch (err) {
return {
ok: false,

View File

@@ -59,6 +59,8 @@ describe("provider auth choice manifest helpers", () => {
method: "api-key",
choiceId: "openai-api-key",
choiceLabel: "OpenAI API key",
assistantPriority: 10,
assistantVisibility: "visible",
onboardingScopes: ["text-inference"],
optionKey: "openaiApiKey",
cliFlag: "--openai-api-key",
@@ -74,6 +76,8 @@ describe("provider auth choice manifest helpers", () => {
methodId: "api-key",
choiceId: "openai-api-key",
choiceLabel: "OpenAI API key",
assistantPriority: 10,
assistantVisibility: "visible",
onboardingScopes: ["text-inference"],
optionKey: "openaiApiKey",
cliFlag: "--openai-api-key",

View File

@@ -1,5 +1,5 @@
import { normalizeProviderIdForAuth } from "../agents/model-selection.js";
import type { OpenClawConfig } from "../config/config.js";
import { normalizeProviderIdForAuth } from "../agents/model-selection.js";
import { normalizePluginsConfig, resolveEffectiveEnableState } from "./config-state.js";
import { loadPluginManifestRegistry } from "./manifest-registry.js";
@@ -10,6 +10,8 @@ export type ProviderAuthChoiceMetadata = {
choiceId: string;
choiceLabel: string;
choiceHint?: string;
assistantPriority?: number;
assistantVisibility?: "visible" | "manual-only";
deprecatedChoiceIds?: string[];
groupId?: string;
groupLabel?: string;
@@ -59,6 +61,12 @@ export function resolveManifestProviderAuthChoices(params?: {
choiceId: choice.choiceId,
choiceLabel: choice.choiceLabel ?? choice.choiceId,
...(choice.choiceHint ? { choiceHint: choice.choiceHint } : {}),
...(choice.assistantPriority !== undefined
? { assistantPriority: choice.assistantPriority }
: {}),
...(choice.assistantVisibility
? { assistantVisibility: choice.assistantVisibility }
: {}),
...(choice.deprecatedChoiceIds
? { deprecatedChoiceIds: choice.deprecatedChoiceIds }
: {}),

View File

@@ -105,6 +105,14 @@ function normalizeProviderWizardSetup(params: {
...(normalizeText(params.setup.choiceHint)
? { choiceHint: normalizeText(params.setup.choiceHint) }
: {}),
...(typeof params.setup.assistantPriority === "number" &&
Number.isFinite(params.setup.assistantPriority)
? { assistantPriority: params.setup.assistantPriority }
: {}),
...(params.setup.assistantVisibility === "manual-only" ||
params.setup.assistantVisibility === "visible"
? { assistantVisibility: params.setup.assistantVisibility }
: {}),
...(normalizeText(params.setup.groupId)
? { groupId: normalizeText(params.setup.groupId) }
: {}),

View File

@@ -1,19 +1,19 @@
import { DEFAULT_PROVIDER } from "../agents/defaults.js";
import { normalizeProviderId } from "../agents/model-selection.js";
import type { OpenClawConfig } from "../config/config.js";
import type { WizardPrompter } from "../wizard/prompts.js";
import {
buildPluginSnapshotCacheEnvKey,
resolvePluginSnapshotCacheTtlMs,
shouldUsePluginSnapshotCache,
} from "./cache-controls.js";
import { resolvePluginProviders } from "./providers.runtime.js";
import type {
ProviderAuthMethod,
ProviderPlugin,
ProviderPluginWizardModelPicker,
ProviderPluginWizardSetup,
} from "./types.js";
import { DEFAULT_PROVIDER } from "../agents/defaults.js";
import { normalizeProviderId } from "../agents/model-selection.js";
import {
buildPluginSnapshotCacheEnvKey,
resolvePluginSnapshotCacheTtlMs,
shouldUsePluginSnapshotCache,
} from "./cache-controls.js";
import { resolvePluginProviders } from "./providers.runtime.js";
export const PROVIDER_PLUGIN_CHOICE_PREFIX = "provider-plugin:";
type ProviderWizardCacheEntry = {
@@ -45,6 +45,8 @@ export type ProviderWizardOption = {
groupLabel: string;
groupHint?: string;
onboardingScopes?: Array<"text-inference" | "image-generation">;
assistantPriority?: number;
assistantVisibility?: "visible" | "manual-only";
};
export type ProviderModelPickerEntry = {
@@ -114,6 +116,13 @@ function buildSetupOptionForMethod(params: {
groupLabel: params.wizard.groupLabel?.trim() || params.provider.label,
groupHint: params.wizard.groupHint?.trim(),
...(params.wizard.onboardingScopes ? { onboardingScopes: params.wizard.onboardingScopes } : {}),
...(typeof params.wizard.assistantPriority === "number" &&
Number.isFinite(params.wizard.assistantPriority)
? { assistantPriority: params.wizard.assistantPriority }
: {}),
...(params.wizard.assistantVisibility
? { assistantVisibility: params.wizard.assistantVisibility }
: {}),
};
}

View File

@@ -1,9 +1,9 @@
import type { IncomingMessage, ServerResponse } from "node:http";
import type { AgentMessage } from "@mariozechner/pi-agent-core";
import type { StreamFn } from "@mariozechner/pi-agent-core";
import type { Api, Model } from "@mariozechner/pi-ai";
import type { ModelRegistry } from "@mariozechner/pi-coding-agent";
import type { Command } from "commander";
import type { IncomingMessage, ServerResponse } from "node:http";
import type {
ApiKeyCredential,
AuthProfileCredential,
@@ -925,6 +925,8 @@ export type ProviderPluginWizardSetup = {
choiceId?: string;
choiceLabel?: string;
choiceHint?: string;
assistantPriority?: number;
assistantVisibility?: "visible" | "manual-only";
groupId?: string;
groupLabel?: string;
groupHint?: string;