mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 20:40:43 +00:00
fix: simplify Crestodian startup greeting
This commit is contained in:
@@ -7,6 +7,7 @@ Docs: https://docs.openclaw.ai
|
||||
### Changes
|
||||
|
||||
- CLI/Crestodian: open interactive Crestodian in the full OpenClaw TUI shell instead of a basic readline prompt.
|
||||
- CLI/Crestodian: shorten the startup greeting to the active planner/model, config state, Gateway probe result, and next debug action instead of dumping every discovered backend.
|
||||
- Diagnostics/OTEL: add bounded outbound message delivery lifecycle diagnostics and export them as low-cardinality delivery spans/metrics without message body, recipient, room, or media-path data. (#71471) Thanks @vincentkoc and @jlapenna.
|
||||
- Diagnostics/OTEL: emit bounded exec-process diagnostics and export them as `openclaw.exec` spans without exposing command text, working directories, or container identifiers. (#71451) Thanks @vincentkoc and @jlapenna.
|
||||
- Diagnostics/OTEL: support `OPENCLAW_OTEL_PRELOADED=1` so the plugin can reuse an already-registered OpenTelemetry SDK while keeping OpenClaw diagnostic listeners wired. (#71450) Thanks @vincentkoc and @jlapenna.
|
||||
|
||||
@@ -18,24 +18,22 @@ Running `openclaw crestodian` starts the same helper explicitly.
|
||||
## What Crestodian shows
|
||||
|
||||
On startup, interactive Crestodian opens the same TUI shell used by
|
||||
`openclaw tui`, with a Crestodian chat backend. The chat log starts with a
|
||||
compact system overview:
|
||||
`openclaw tui`, with a Crestodian chat backend. The chat log starts with a short
|
||||
greeting:
|
||||
|
||||
- config path and validity
|
||||
- configured agents and the default agent
|
||||
- default model
|
||||
- local Codex and Claude Code CLI availability
|
||||
- OpenAI and Anthropic API-key presence
|
||||
- planner mode (`deterministic` or model-assisted through the configured model)
|
||||
- local docs path or the public docs URL
|
||||
- local source path for Git checkouts, otherwise the OpenClaw GitHub source URL
|
||||
- gateway reachability
|
||||
- the immediate recommended next step
|
||||
- when to start Crestodian
|
||||
- the model or deterministic planner path Crestodian is actually using
|
||||
- config validity and the default agent
|
||||
- Gateway reachability from the first startup probe
|
||||
- the next debug action Crestodian can take
|
||||
|
||||
It does not dump secrets or load plugin CLI commands just to start. The TUI
|
||||
still provides the normal header, chat log, status line, footer, autocomplete,
|
||||
and editor controls.
|
||||
|
||||
Use `status` for the detailed inventory with config path, docs/source paths,
|
||||
local CLI probes, API-key presence, agents, model, and Gateway details.
|
||||
|
||||
Crestodian uses the same OpenClaw reference discovery as regular agents. In a Git checkout,
|
||||
it points itself at local `docs/` and the local source tree. In an npm package install, it
|
||||
uses the bundled package docs and links to
|
||||
|
||||
@@ -53,7 +53,8 @@ describe("loadCrestodianOverview", () => {
|
||||
)}\n`,
|
||||
);
|
||||
|
||||
const { formatCrestodianOverview, loadCrestodianOverview } = await import("./overview.js");
|
||||
const { formatCrestodianOverview, formatCrestodianStartupMessage, loadCrestodianOverview } =
|
||||
await import("./overview.js");
|
||||
const overview = await loadCrestodianOverview();
|
||||
|
||||
expect(overview.config).toMatchObject({
|
||||
@@ -72,7 +73,15 @@ describe("loadCrestodianOverview", () => {
|
||||
expect(overview.references.docsPath).toMatch(/docs$/);
|
||||
expect(overview.references.sourceUrl).toBe("https://github.com/openclaw/openclaw");
|
||||
expect(formatCrestodianOverview(overview)).toContain(
|
||||
'Next: say "gateway status" or "restart gateway"',
|
||||
'Next: run "gateway status" or "restart gateway"',
|
||||
);
|
||||
const startup = formatCrestodianStartupMessage(overview);
|
||||
expect(startup).toContain("## Hi, I'm Crestodian.");
|
||||
expect(startup).toContain("Using: openai/gpt-5.2");
|
||||
expect(startup).toContain("Gateway: not reachable");
|
||||
expect(startup).toContain("I can start debugging with `gateway status`");
|
||||
expect(startup).not.toContain("Codex:");
|
||||
expect(startup).not.toContain("Claude Code:");
|
||||
expect(startup).not.toContain("API keys:");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -237,16 +237,70 @@ export function formatCrestodianOverview(overview: CrestodianOverview): string {
|
||||
|
||||
export function recommendCrestodianNextStep(overview: CrestodianOverview): string {
|
||||
if (!overview.config.exists) {
|
||||
return 'say "setup" to create a starter config';
|
||||
return 'run "setup" to create a starter config';
|
||||
}
|
||||
if (!overview.config.valid) {
|
||||
return 'say "validate config" or "doctor" to inspect the config';
|
||||
return 'run "validate config" or "doctor" to inspect the config';
|
||||
}
|
||||
if (!overview.defaultModel) {
|
||||
return 'say "setup" or "set default model <provider/model>"';
|
||||
return 'run "setup" or "set default model <provider/model>"';
|
||||
}
|
||||
if (!overview.gateway.reachable) {
|
||||
return 'say "gateway status" or "restart gateway"';
|
||||
return 'run "gateway status" or "restart gateway"';
|
||||
}
|
||||
return 'say "talk to agent" to enter your default agent';
|
||||
return 'run "talk to agent" to enter your default agent';
|
||||
}
|
||||
|
||||
function formatStartupConfigStatus(overview: CrestodianOverview): string {
|
||||
if (!overview.config.exists) {
|
||||
return "missing";
|
||||
}
|
||||
return overview.config.valid ? "valid" : "invalid";
|
||||
}
|
||||
|
||||
function formatStartupUse(overview: CrestodianOverview): string {
|
||||
if (overview.defaultModel) {
|
||||
return `Using: ${overview.defaultModel} for fuzzy local planning.`;
|
||||
}
|
||||
return "Using: deterministic typed commands until we configure a model.";
|
||||
}
|
||||
|
||||
function formatStartupGatewayStatus(overview: CrestodianOverview): string {
|
||||
if (overview.gateway.reachable) {
|
||||
return `Gateway: reachable at ${overview.gateway.url}.`;
|
||||
}
|
||||
return `Gateway: not reachable at ${overview.gateway.url}; I already did the first probe.`;
|
||||
}
|
||||
|
||||
function formatStartupAction(overview: CrestodianOverview): string {
|
||||
if (!overview.config.exists) {
|
||||
return "I can start by creating a starter config with `setup`.";
|
||||
}
|
||||
if (!overview.config.valid) {
|
||||
return "I can start debugging with `validate config` or `doctor`.";
|
||||
}
|
||||
if (!overview.defaultModel) {
|
||||
return "I can start by choosing a model with `setup`.";
|
||||
}
|
||||
if (!overview.gateway.reachable) {
|
||||
return "I can start debugging with `gateway status`, or queue `restart gateway` for approval.";
|
||||
}
|
||||
return "Everything basic is reachable. Use `talk to agent` when you want the normal agent.";
|
||||
}
|
||||
|
||||
export function formatCrestodianStartupMessage(overview: CrestodianOverview): string {
|
||||
const agent = overview.agents.find((entry) => entry.id === overview.defaultAgentId);
|
||||
const agentLabel = agent?.name
|
||||
? `${overview.defaultAgentId} (${agent.name})`
|
||||
: overview.defaultAgentId;
|
||||
return [
|
||||
"## Hi, I'm Crestodian.",
|
||||
"",
|
||||
"- Start me when setup, config, Gateway, model choice, or agent routing feels off.",
|
||||
`- ${formatStartupUse(overview)}`,
|
||||
`- Config: ${formatStartupConfigStatus(overview)}. Default agent: ${agentLabel}.`,
|
||||
`- ${formatStartupGatewayStatus(overview)}`,
|
||||
"",
|
||||
formatStartupAction(overview),
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
type CrestodianCommandDeps,
|
||||
type CrestodianOperation,
|
||||
} from "./operations.js";
|
||||
import { formatCrestodianOverview, loadCrestodianOverview } from "./overview.js";
|
||||
import { formatCrestodianStartupMessage, loadCrestodianOverview } from "./overview.js";
|
||||
|
||||
export type CrestodianTuiOptions = {
|
||||
yes?: boolean;
|
||||
@@ -75,14 +75,6 @@ function splitModelRef(ref: string | undefined): { provider?: string; model?: st
|
||||
};
|
||||
}
|
||||
|
||||
function crestodianWelcome(overviewText: string): string {
|
||||
return [
|
||||
overviewText,
|
||||
"",
|
||||
"Say: status, doctor, health, gateway status, restart gateway, agents, models, set default model <provider/model>, talk to agent, audit, or quit.",
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
class CrestodianTuiBackend implements TuiBackend {
|
||||
readonly connection = { url: "crestodian local" };
|
||||
|
||||
@@ -212,7 +204,7 @@ class CrestodianTuiBackend implements TuiBackend {
|
||||
this.messages.splice(
|
||||
0,
|
||||
this.messages.length,
|
||||
message("assistant", crestodianWelcome(formatCrestodianOverview(overview))),
|
||||
message("assistant", formatCrestodianStartupMessage(overview)),
|
||||
);
|
||||
return { ok: true };
|
||||
}
|
||||
@@ -325,10 +317,7 @@ export async function runCrestodianTui(
|
||||
let nextInput: string | undefined;
|
||||
for (;;) {
|
||||
const overview = await loadCrestodianOverview();
|
||||
const backend = new CrestodianTuiBackend(
|
||||
opts,
|
||||
crestodianWelcome(formatCrestodianOverview(overview)),
|
||||
);
|
||||
const backend = new CrestodianTuiBackend(opts, formatCrestodianStartupMessage(overview));
|
||||
await runTui({
|
||||
local: true,
|
||||
session: CRESTODIAN_SESSION_KEY,
|
||||
|
||||
Reference in New Issue
Block a user