mirror of
https://github.com/lWolvesl/claw-code.git
synced 2026-04-02 07:41:52 +08:00
Make model inspection and switching feel more like a real CLI surface
Replace terse /model strings with sectioned model reports that show the active model and preserved session context, and use a structured switch report when the model changes. This keeps the behavior honest while making model management feel more intentional and Claude-like. Constraint: Model switching must preserve the current session and avoid adding any fake model catalog or validation layer Rejected: Add a hardcoded model list or aliases | would create drift with actual backend-supported model names Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep /model output informational and backend-agnostic unless the runtime gains authoritative model discovery Tested: cargo fmt --manifest-path ./rust/Cargo.toml --all; cargo clippy --manifest-path ./rust/Cargo.toml --workspace --all-targets -- -D warnings; cargo test --manifest-path ./rust/Cargo.toml --workspace Not-tested: Manual interactive switching across multiple real Anthropic model names
This commit is contained in:
@@ -269,6 +269,28 @@ struct StatusUsage {
|
|||||||
estimated_tokens: usize,
|
estimated_tokens: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_model_report(model: &str, message_count: usize, turns: u32) -> String {
|
||||||
|
format!(
|
||||||
|
"Model
|
||||||
|
Current model {model}
|
||||||
|
Session messages {message_count}
|
||||||
|
Session turns {turns}
|
||||||
|
|
||||||
|
Usage
|
||||||
|
Inspect current model with /model
|
||||||
|
Switch models with /model <name>"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn format_model_switch_report(previous: &str, next: &str, message_count: usize) -> String {
|
||||||
|
format!(
|
||||||
|
"Model updated
|
||||||
|
Previous {previous}
|
||||||
|
Current {next}
|
||||||
|
Preserved msgs {message_count}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn run_resume_command(
|
fn run_resume_command(
|
||||||
session_path: &Path,
|
session_path: &Path,
|
||||||
session: &Session,
|
session: &Session,
|
||||||
@@ -489,19 +511,38 @@ impl LiveCli {
|
|||||||
|
|
||||||
fn set_model(&mut self, model: Option<String>) -> Result<(), Box<dyn std::error::Error>> {
|
fn set_model(&mut self, model: Option<String>) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let Some(model) = model else {
|
let Some(model) = model else {
|
||||||
println!("Current model: {}", self.model);
|
println!(
|
||||||
|
"{}",
|
||||||
|
format_model_report(
|
||||||
|
&self.model,
|
||||||
|
self.runtime.session().messages.len(),
|
||||||
|
self.runtime.usage().turns(),
|
||||||
|
)
|
||||||
|
);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
if model == self.model {
|
if model == self.model {
|
||||||
println!("Model already set to {model}.");
|
println!(
|
||||||
|
"{}",
|
||||||
|
format_model_report(
|
||||||
|
&self.model,
|
||||||
|
self.runtime.session().messages.len(),
|
||||||
|
self.runtime.usage().turns(),
|
||||||
|
)
|
||||||
|
);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let previous = self.model.clone();
|
||||||
let session = self.runtime.session().clone();
|
let session = self.runtime.session().clone();
|
||||||
|
let message_count = session.messages.len();
|
||||||
self.runtime = build_runtime(session, model.clone(), self.system_prompt.clone(), true)?;
|
self.runtime = build_runtime(session, model.clone(), self.system_prompt.clone(), true)?;
|
||||||
self.model.clone_from(&model);
|
self.model.clone_from(&model);
|
||||||
println!("Switched model to {model}.");
|
println!(
|
||||||
|
"{}",
|
||||||
|
format_model_switch_report(&previous, &model, message_count)
|
||||||
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1193,9 +1234,10 @@ fn print_help() {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::{
|
use super::{
|
||||||
format_status_report, normalize_permission_mode, parse_args, render_init_claude_md,
|
format_model_report, format_model_switch_report, format_status_report,
|
||||||
render_repl_help, resume_supported_slash_commands, status_context, CliAction, SlashCommand,
|
normalize_permission_mode, parse_args, render_init_claude_md, render_repl_help,
|
||||||
StatusUsage, DEFAULT_MODEL,
|
resume_supported_slash_commands, status_context, CliAction, SlashCommand, StatusUsage,
|
||||||
|
DEFAULT_MODEL,
|
||||||
};
|
};
|
||||||
use runtime::{ContentBlock, ConversationMessage, MessageRole};
|
use runtime::{ContentBlock, ConversationMessage, MessageRole};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
@@ -1310,6 +1352,24 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn model_report_uses_sectioned_layout() {
|
||||||
|
let report = format_model_report("claude-sonnet", 12, 4);
|
||||||
|
assert!(report.contains("Model"));
|
||||||
|
assert!(report.contains("Current model claude-sonnet"));
|
||||||
|
assert!(report.contains("Session messages 12"));
|
||||||
|
assert!(report.contains("Switch models with /model <name>"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn model_switch_report_preserves_context_summary() {
|
||||||
|
let report = format_model_switch_report("claude-sonnet", "claude-opus", 9);
|
||||||
|
assert!(report.contains("Model updated"));
|
||||||
|
assert!(report.contains("Previous claude-sonnet"));
|
||||||
|
assert!(report.contains("Current claude-opus"));
|
||||||
|
assert!(report.contains("Preserved msgs 9"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn status_line_reports_model_and_token_totals() {
|
fn status_line_reports_model_and_token_totals() {
|
||||||
let status = format_status_report(
|
let status = format_status_report(
|
||||||
|
|||||||
Reference in New Issue
Block a user