mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-08-27 08:00:17 +00:00
feat: add polished boot screen on CLI startup (#118)
* feat: add polished boot screen on CLI startup Replace the minimal one-liner REPL banner with an ANSI-styled status panel that summarizes the agent's runtime state after initialization: model, database, tool count, enabled features, active channels, and the gateway URL. The boot screen is shown only in interactive CLI mode (skipped for single-message -m mode). Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: address PR review feedback on boot screen - Stop logging gateway auth token in tracing::info! (security) - Use info.agent_name instead of hardcoded "IronClaw" in header - Display embeddings provider in features line: "embeddings (openai)" - Add Display impl for DatabaseBackend, simplify main.rs match Co-Authored-By: Claude Opus 4.6 <[email protected]> --------- Co-authored-by: Claude Opus 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
7c553b0973
commit
63302ab406
+55
-7
@@ -338,7 +338,10 @@ async fn main() -> anyhow::Result<()> {
|
||||
let repl_channel = if let Some(ref msg) = cli.message {
|
||||
Some(ReplChannel::with_message(msg.clone()))
|
||||
} else if config.channels.cli.enabled {
|
||||
Some(ReplChannel::new())
|
||||
let repl = ReplChannel::new();
|
||||
// Suppress the one-liner banner; boot screen will be shown instead.
|
||||
repl.suppress_banner();
|
||||
Some(repl)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@@ -886,12 +889,14 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
// Initialize channel manager
|
||||
let mut channels = ChannelManager::new();
|
||||
let mut channel_names: Vec<String> = Vec::new();
|
||||
|
||||
if let Some(repl) = repl_channel {
|
||||
channels.add(Box::new(repl));
|
||||
if cli.message.is_some() {
|
||||
tracing::info!("Single message mode");
|
||||
} else {
|
||||
channel_names.push("repl".to_string());
|
||||
tracing::info!("REPL mode enabled");
|
||||
}
|
||||
}
|
||||
@@ -1027,6 +1032,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
channel_names.push(channel_name.clone());
|
||||
channels.add(Box::new(SharedWasmChannel::new(channel_arc)));
|
||||
}
|
||||
|
||||
@@ -1071,6 +1077,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
.parse()
|
||||
.expect("HttpConfig host:port must be a valid SocketAddr"),
|
||||
);
|
||||
channel_names.push("http".to_string());
|
||||
channels.add(Box::new(http_channel));
|
||||
tracing::info!(
|
||||
"HTTP channel enabled on {}:{}",
|
||||
@@ -1147,6 +1154,7 @@ async fn main() -> anyhow::Result<()> {
|
||||
);
|
||||
|
||||
// Add web gateway channel if configured
|
||||
let mut gateway_url: Option<String> = None;
|
||||
if let Some(ref gw_config) = config.channels.gateway {
|
||||
let mut gw = GatewayChannel::new(gw_config.clone());
|
||||
if let Some(ref ws) = workspace {
|
||||
@@ -1179,21 +1187,29 @@ async fn main() -> anyhow::Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
gateway_url = Some(format!(
|
||||
"http://{}:{}/?token={}",
|
||||
gw_config.host,
|
||||
gw_config.port,
|
||||
gw.auth_token()
|
||||
));
|
||||
|
||||
tracing::info!(
|
||||
"Web gateway enabled on {}:{}",
|
||||
gw_config.host,
|
||||
gw_config.port
|
||||
);
|
||||
tracing::info!(
|
||||
"Web UI: http://{}:{}/?token={}",
|
||||
gw_config.host,
|
||||
gw_config.port,
|
||||
gw.auth_token()
|
||||
);
|
||||
tracing::info!("Web UI: http://{}:{}/", gw_config.host, gw_config.port);
|
||||
|
||||
channel_names.push("gateway".to_string());
|
||||
channels.add(Box::new(gw));
|
||||
}
|
||||
|
||||
// Capture boot screen info before moving Arcs into AgentDeps.
|
||||
let boot_tool_count = tools.count();
|
||||
let boot_llm_model = llm.model_name().to_string();
|
||||
let boot_cheap_model = cheap_llm.as_ref().map(|c| c.model_name().to_string());
|
||||
|
||||
// Create and run the agent
|
||||
let deps = AgentDeps {
|
||||
store: db,
|
||||
@@ -1217,6 +1233,38 @@ async fn main() -> anyhow::Result<()> {
|
||||
|
||||
tracing::info!("Agent initialized, starting main loop...");
|
||||
|
||||
// Print boot screen for interactive CLI mode (not single-message mode).
|
||||
if config.channels.cli.enabled && cli.message.is_none() {
|
||||
let boot_info = ironclaw::boot_screen::BootInfo {
|
||||
version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
agent_name: config.agent.name.clone(),
|
||||
llm_backend: config.llm.backend.to_string(),
|
||||
llm_model: boot_llm_model,
|
||||
cheap_model: boot_cheap_model,
|
||||
db_backend: if cli.no_db {
|
||||
"none".to_string()
|
||||
} else {
|
||||
config.database.backend.to_string()
|
||||
},
|
||||
db_connected: !cli.no_db,
|
||||
tool_count: boot_tool_count,
|
||||
gateway_url,
|
||||
embeddings_enabled: config.embeddings.enabled,
|
||||
embeddings_provider: if config.embeddings.enabled {
|
||||
Some(config.embeddings.provider.clone())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
heartbeat_enabled: config.heartbeat.enabled,
|
||||
heartbeat_interval_secs: config.heartbeat.interval_secs,
|
||||
sandbox_enabled: config.sandbox.enabled,
|
||||
claude_code_enabled: config.claude_code.enabled,
|
||||
routines_enabled: config.routines.enabled,
|
||||
channels: channel_names,
|
||||
};
|
||||
ironclaw::boot_screen::print_boot_screen(&boot_info);
|
||||
}
|
||||
|
||||
// Run the agent (blocks until shutdown)
|
||||
agent.run().await?;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user