onboard: clearer security disclaimer, loading spinners, api key placeholder

This commit is contained in:
Patrick Erichsen
2026-04-20 19:38:46 -07:00
committed by Peter Steinberger
parent 49db424c80
commit 7752e3b30f
6 changed files with 65 additions and 35 deletions

View File

@@ -6,6 +6,7 @@ Docs: https://docs.openclaw.ai
### Changes
- Onboard/wizard: restyle the setup security disclaimer with a single yellow warning banner, section headings and bulleted checklists, and un-dim the note body so key guidance is easy to scan; add a loading spinner during the initial model catalog load so the wizard no longer goes blank while it runs; add an "API key" placeholder to provider API key prompts.
- Agents/prompts: strengthen the default system prompt and OpenAI GPT-5 overlay with clearer completion bias, live-state checks, weak-result recovery, and verification-before-final guidance.
- Models/costs: support tiered model pricing from cached catalogs and configured models, and include bundled Moonshot Kimi K2.6/K2.5 cost estimates for token-usage reports. (#67605) Thanks @sliverp.
- Sessions/Maintenance: enforce the built-in entry cap and age prune by default, and prune oversized stores at load time so accumulated cron/executor session backlogs cannot OOM the gateway before the write path runs. (#69404) Thanks @bobrenze-bot.

View File

@@ -427,7 +427,13 @@ export async function promptDefaultModel(
const resolvedKey = modelKey(resolved.provider, resolved.model);
const configuredKey = configuredRaw ? resolvedKey : "";
const catalog = await loadModelCatalog({ config: cfg, useCache: false });
const catalogProgress = params.prompter.progress("Loading available models");
let catalog: Awaited<ReturnType<typeof loadModelCatalog>>;
try {
catalog = await loadModelCatalog({ config: cfg, useCache: false });
} finally {
catalogProgress.stop();
}
if (catalog.length === 0) {
return promptManualModel({
prompter: params.prompter,
@@ -532,6 +538,7 @@ export async function promptDefaultModel(
message: params.message ?? "Default model",
options,
initialValue,
searchable: true,
});
const selectedValue = selection ?? "";
if (selectedValue === KEEP_VALUE) {
@@ -603,7 +610,13 @@ export async function promptModelAllowlist(params: {
? initialSeeds.filter((key) => allowedKeySet.has(key))
: initialSeeds;
const catalog = await loadModelCatalog({ config: cfg, useCache: false });
const allowlistProgress = params.prompter.progress("Loading available models");
let catalog: Awaited<ReturnType<typeof loadModelCatalog>>;
try {
catalog = await loadModelCatalog({ config: cfg, useCache: false });
} finally {
allowlistProgress.stop();
}
if (catalog.length === 0 && allowedKeys.length === 0) {
const raw = await params.prompter.text({
message:

View File

@@ -214,6 +214,7 @@ export async function ensureApiKeyFromEnvOrPrompt(params: {
const key = await params.prompter.text({
message: params.promptMessage,
placeholder: "API key",
validate: params.validate,
});
const apiKey = params.normalize(key ?? "");

View File

@@ -186,5 +186,6 @@ export function note(message: string, title?: string) {
const columns = resolveNoteColumns(process.stdout.columns);
clackNote(wrapNoteMessage(message, { columns }), stylePromptTitle(title), {
output: createNoteOutput(columns),
format: (line) => line,
});
}

View File

@@ -0,0 +1,40 @@
import chalk from "chalk";
import { formatCliCommand } from "../cli/command-format.js";
import { theme } from "../terminal/theme.js";
export const SECURITY_NOTE_TITLE = "Security disclaimer";
export const SECURITY_CONFIRM_MESSAGE =
"I understand this is personal-by-default and shared/multi-user use requires lock-down. Continue?";
const heading = (text: string) => chalk.bold(text);
export const SECURITY_NOTE_MESSAGE = [
theme.warn("⚠ OpenClaw is in Beta - expect sharp edges"),
"- By default, OpenClaw is a personal agent: one trusted operator boundary.",
"- This bot can read files and run actions if tools are enabled.",
"- A bad prompt can trick it into doing unsafe things.",
"",
heading("How OpenClaw treats trust"),
"- OpenClaw is not a hostile multi-tenant boundary by default.",
"- If multiple users can message one tool-enabled agent, they share that delegated tool authority.",
"",
heading("When not to run OpenClaw"),
"- If youre not comfortable with security hardening and access control, dont run OpenClaw.",
"- Ask someone experienced to help before enabling tools or exposing it to the internet.",
"",
heading("Recommended baseline"),
"- Pairing/allowlists + mention gating.",
"- Multi-user/shared inbox: split trust boundaries (separate gateway/credentials, ideally separate OS users/hosts).",
"- Sandbox + least-privilege tools.",
"- Shared inboxes: isolate DM sessions (session.dmScope: per-channel-peer) and keep tool access minimal.",
"- Keep secrets out of the agents reachable filesystem.",
"- Use the strongest available model for any bot with tools or untrusted inboxes.",
"",
heading("Run regularly"),
formatCliCommand("openclaw security audit --deep"),
formatCliCommand("openclaw security audit --fix"),
"",
heading("Learn more"),
"- https://docs.openclaw.ai/gateway/security",
].join("\n");

View File

@@ -19,6 +19,11 @@ import { defaultRuntime } from "../runtime.js";
import { resolveUserPath } from "../utils.js";
import { WizardCancelledError, type WizardPrompter } from "./prompts.js";
import { resolveSetupSecretInputString } from "./setup.secret-input.js";
import {
SECURITY_CONFIRM_MESSAGE,
SECURITY_NOTE_MESSAGE,
SECURITY_NOTE_TITLE,
} from "./setup.security-note.js";
import type { QuickstartGatewayDefaults, WizardFlow } from "./setup.types.js";
type AuthChoiceModule = typeof import("../commands/auth-choice.js");
@@ -108,41 +113,10 @@ async function requireRiskAcknowledgement(params: {
return;
}
await params.prompter.note(
[
"Security warning — please read.",
"",
"OpenClaw is a hobby project and still in beta. Expect sharp edges.",
"By default, OpenClaw is a personal agent: one trusted operator boundary.",
"This bot can read files and run actions if tools are enabled.",
"A bad prompt can trick it into doing unsafe things.",
"",
"OpenClaw is not a hostile multi-tenant boundary by default.",
"If multiple users can message one tool-enabled agent, they share that delegated tool authority.",
"",
"If youre not comfortable with security hardening and access control, dont run OpenClaw.",
"Ask someone experienced to help before enabling tools or exposing it to the internet.",
"",
"Recommended baseline:",
"- Pairing/allowlists + mention gating.",
"- Multi-user/shared inbox: split trust boundaries (separate gateway/credentials, ideally separate OS users/hosts).",
"- Sandbox + least-privilege tools.",
"- Shared inboxes: isolate DM sessions (`session.dmScope: per-channel-peer`) and keep tool access minimal.",
"- Keep secrets out of the agents reachable filesystem.",
"- Use the strongest available model for any bot with tools or untrusted inboxes.",
"",
"Run regularly:",
"openclaw security audit --deep",
"openclaw security audit --fix",
"",
"Must read: https://docs.openclaw.ai/gateway/security",
].join("\n"),
"Security",
);
await params.prompter.note(SECURITY_NOTE_MESSAGE, SECURITY_NOTE_TITLE);
const ok = await params.prompter.confirm({
message:
"I understand this is personal-by-default and shared/multi-user use requires lock-down. Continue?",
message: SECURITY_CONFIRM_MESSAGE,
initialValue: false,
});
if (!ok) {