Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 13 additions & 14 deletions rust/crates/api/src/providers/anthropic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -600,8 +600,9 @@ fn jitter_for_base(base: Duration) -> Duration {
}
let raw_nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|elapsed| u64::try_from(elapsed.as_nanos()).unwrap_or(u64::MAX))
.unwrap_or(0);
.map_or(0, |elapsed| {
u64::try_from(elapsed.as_nanos()).unwrap_or(u64::MAX)
});
let tick = JITTER_COUNTER.fetch_add(1, Ordering::Relaxed);
// splitmix64 finalizer — mixes the low bits so large bases still see
// jitter across their full range instead of being clamped to subsec nanos.
Expand Down Expand Up @@ -844,19 +845,17 @@ impl MessageStream {
StreamEvent::MessageDelta(MessageDeltaEvent { usage, .. }) => {
self.latest_usage = Some(usage.clone());
}
StreamEvent::MessageStop(_) => {
if !self.usage_recorded {
if let (Some(prompt_cache), Some(usage)) =
(&self.prompt_cache, self.latest_usage.as_ref())
{
let record = prompt_cache.record_usage(&self.request, usage);
*self
.last_prompt_cache_record
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = Some(record);
}
self.usage_recorded = true;
StreamEvent::MessageStop(_) if !self.usage_recorded => {
if let (Some(prompt_cache), Some(usage)) =
(&self.prompt_cache, self.latest_usage.as_ref())
{
let record = prompt_cache.record_usage(&self.request, usage);
*self
.last_prompt_cache_record
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner) = Some(record);
}
self.usage_recorded = true;
}
_ => {}
}
Expand Down
4 changes: 1 addition & 3 deletions rust/crates/api/src/providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,9 +272,7 @@ pub fn max_tokens_for_model(model: &str) -> u32 {
64_000
};

model_token_limit(model)
.map(|limit| heuristic.min(limit.max_output_tokens))
.unwrap_or(heuristic)
model_token_limit(model).map_or(heuristic, |limit| heuristic.min(limit.max_output_tokens))
}

/// Returns the effective max output tokens for a model, preferring a plugin
Expand Down
10 changes: 5 additions & 5 deletions rust/crates/api/src/providers/openai_compat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,8 +327,9 @@ fn jitter_for_base(base: Duration) -> Duration {
}
let raw_nanos = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|elapsed| u64::try_from(elapsed.as_nanos()).unwrap_or(u64::MAX))
.unwrap_or(0);
.map_or(0, |elapsed| {
u64::try_from(elapsed.as_nanos()).unwrap_or(u64::MAX)
});
let tick = JITTER_COUNTER.fetch_add(1, Ordering::Relaxed);
let mut mixed = raw_nanos
.wrapping_add(tick)
Expand Down Expand Up @@ -855,7 +856,7 @@ pub fn is_reasoning_model(model: &str) -> bool {
|| canonical.contains("thinking")
}

/// Returns true for OpenAI-compatible DeepSeek V4 models that require prior
/// Returns true for OpenAI-compatible `DeepSeek` V4 models that require prior
/// assistant reasoning to be echoed back as `reasoning_content` in history.
#[must_use]
pub fn model_requires_reasoning_content_in_history(model: &str) -> bool {
Expand Down Expand Up @@ -1083,8 +1084,7 @@ pub fn translate_message(message: &InputMessage, model: &str) -> Vec<Value> {
}
Some(msg)
}
InputContentBlock::Thinking { .. } => None,
InputContentBlock::ToolUse { .. } => None,
InputContentBlock::Thinking { .. } | InputContentBlock::ToolUse { .. } => None,
})
.collect(),
}
Expand Down
1 change: 0 additions & 1 deletion rust/crates/mock-anthropic-service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,6 @@ fn detect_scenario(request: &MessageRequest) -> Option<Scenario> {
.split_whitespace()
.find_map(|token| token.strip_prefix(SCENARIO_PREFIX))
.and_then(Scenario::parse),
InputContentBlock::Thinking { .. } => None,
_ => None,
})
})
Expand Down
3 changes: 1 addition & 2 deletions rust/crates/runtime/src/compact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,7 @@ fn summarize_messages(messages: &[ConversationMessage]) -> String {
.filter_map(|block| match block {
ContentBlock::ToolUse { name, .. } => Some(name.as_str()),
ContentBlock::ToolResult { tool_name, .. } => Some(tool_name.as_str()),
ContentBlock::Text { .. } => None,
ContentBlock::Thinking { .. } => None,
ContentBlock::Text { .. } | ContentBlock::Thinking { .. } => None,
})
.collect::<Vec<_>>();
tool_names.sort_unstable();
Expand Down
2 changes: 1 addition & 1 deletion rust/crates/runtime/src/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,7 @@ fn format_hook_failure(command: &str, code: i32, stdout: Option<&str>, stderr: &

fn shell_command(command: &str) -> CommandWithStdin {
#[cfg(windows)]
let mut command_builder = {
let command_builder = {
let mut command_builder = Command::new("cmd");
command_builder.arg("/C").arg(command);
CommandWithStdin::new(command_builder)
Expand Down
3 changes: 1 addition & 2 deletions rust/crates/runtime/src/sandbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,8 +298,7 @@ fn unshare_user_namespace_works() -> bool {
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
.is_ok_and(|s| s.success())
})
}

Expand Down
43 changes: 19 additions & 24 deletions rust/crates/rusty-claude-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ const DEFAULT_MODEL: &str = "claude-opus-4-6";
enum ModelSource {
/// Explicit `--model` / `--model=` CLI flag.
Flag,
/// ANTHROPIC_MODEL environment variable (when no flag was passed).
/// `ANTHROPIC_MODEL` environment variable (when no flag was passed).
Env,
/// `model` key in `.claw.json` / `.claw/settings.json` (when neither
/// flag nor env set it).
Config,
/// Compiled-in DEFAULT_MODEL fallback.
/// Compiled-in `DEFAULT_MODEL` fallback.
Default,
}

Expand Down Expand Up @@ -244,7 +244,7 @@ Run `claw --help` for usage."

/// #77: Classify a stringified error message into a machine-readable kind.
///
/// Returns a snake_case token that downstream consumers can switch on instead
/// Returns a `snake_case` token that downstream consumers can switch on instead
/// of regex-scraping the prose. The classification is best-effort prefix/keyword
/// matching against the error messages produced throughout the CLI surface.
fn classify_error_kind(message: &str) -> &'static str {
Expand Down Expand Up @@ -278,9 +278,9 @@ fn classify_error_kind(message: &str) -> &'static str {
}
}

/// #77: Split a multi-line error message into (short_reason, optional_hint).
/// #77: Split a multi-line error message into (`short_reason`, `optional_hint`).
///
/// The short_reason is the first line (up to the first newline), and the hint
/// The `short_reason` is the first line (up to the first newline), and the hint
/// is the remaining text or `None` if there's no newline. This prevents the
/// runbook prose from being stuffed into the `error` field that downstream
/// parsers expect to be the short reason alone.
Expand Down Expand Up @@ -940,9 +940,9 @@ fn parse_args(args: &[String]) -> Result<CliAction, String> {
// only intercepts the bare single-word form. Catch all multi-word
// forms here and return a structured guidance error so no network
// call or session is created.
"permissions" => Err(format!(
"`claw permissions` is a slash command. Start `claw` and run `/permissions` inside the REPL.\n Usage /permissions [read-only|workspace-write|danger-full-access]"
)),
"permissions" => Err(
"`claw permissions` is a slash command. Start `claw` and run `/permissions` inside the REPL.\n Usage /permissions [read-only|workspace-write|danger-full-access]".to_string()
),
"skills" => {
let args = join_optional_args(&rest[1..]);
match classify_skills_slash_command(args.as_deref()) {
Expand Down Expand Up @@ -3560,7 +3560,7 @@ fn run_resume_command(
message: Some(handle_agents_slash_command(args.as_deref(), &cwd)?),
json: Some(
serde_json::to_value(handle_agents_slash_command_json(args.as_deref(), &cwd)?)
.unwrap_or_else(|_| serde_json::json!(null)),
.unwrap_or(serde_json::Value::Null),
),
})
}
Expand All @@ -3579,14 +3579,12 @@ fn run_resume_command(
}
SlashCommand::Plugins { action, target } => {
// Only list is supported in resume mode (no runtime to reload)
match action.as_deref() {
Some("install") | Some("uninstall") | Some("enable") | Some("disable")
| Some("update") => {
return Err(
"resumed /plugins mutations are interactive-only; start `claw` and run `/plugins` in the REPL".into(),
);
}
_ => {}
if let Some("install" | "uninstall" | "enable" | "disable" | "update") =
action.as_deref()
{
return Err(
"resumed /plugins mutations are interactive-only; start `claw` and run `/plugins` in the REPL".into(),
);
}
let cwd = env::current_dir()?;
let loader = ConfigLoader::default_for(&cwd);
Expand Down Expand Up @@ -5136,7 +5134,7 @@ impl LiveCli {
// Propagate ok:false → non-zero exit so automation callers
// can rely on exit code instead of inspecting the envelope.
// (#68: mcp error envelopes previously always exited 0.)
let is_error = value.get("ok").and_then(|v| v.as_bool()) == Some(false);
let is_error = value.get("ok").and_then(serde_json::Value::as_bool) == Some(false);
println!("{}", serde_json::to_string_pretty(&value)?);
if is_error {
std::process::exit(1);
Expand Down Expand Up @@ -6563,8 +6561,7 @@ fn render_diff_report_for(cwd: &Path) -> Result<String, Box<dyn std::error::Erro
.args(["rev-parse", "--is-inside-work-tree"])
.current_dir(cwd)
.output()
.map(|o| o.status.success())
.unwrap_or(false);
.is_ok_and(|o| o.status.success());
if !in_git_repo {
return Ok(format!(
"Diff\n Result no git repository\n Detail {} is not inside a git project",
Expand Down Expand Up @@ -6596,8 +6593,7 @@ fn render_diff_json_for(cwd: &Path) -> Result<serde_json::Value, Box<dyn std::er
.args(["rev-parse", "--is-inside-work-tree"])
.current_dir(cwd)
.output()
.map(|o| o.status.success())
.unwrap_or(false);
.is_ok_and(|o| o.status.success());
if !in_git_repo {
return Ok(serde_json::json!({
"kind": "diff",
Expand Down Expand Up @@ -6825,8 +6821,7 @@ fn command_exists(name: &str) -> bool {
Command::new("which")
.arg(name)
.output()
.map(|output| output.status.success())
.unwrap_or(false)
.is_ok_and(|output| output.status.success())
}

fn write_temp_text_file(
Expand Down
16 changes: 10 additions & 6 deletions rust/crates/tools/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1996,8 +1996,7 @@ fn git_ref_exists(reference: &str) -> bool {
Command::new("git")
.args(["rev-parse", "--verify", "--quiet", reference])
.output()
.map(|output| output.status.success())
.unwrap_or(false)
.is_ok_and(|output| output.status.success())
}

fn git_stdout(args: &[&str]) -> Option<String> {
Expand Down Expand Up @@ -4691,7 +4690,10 @@ async fn stream_with_provider(
},
ApiStreamEvent::ContentBlockStop(stop) => {
if let Some((thinking, signature)) = pending_thinking.remove(&stop.index) {
events.push(AssistantEvent::Thinking { thinking, signature });
events.push(AssistantEvent::Thinking {
thinking,
signature,
});
}
if let Some((id, name, input)) = pending_tools.remove(&stop.index) {
events.push(AssistantEvent::ToolUse { id, name, input });
Expand Down Expand Up @@ -4859,7 +4861,10 @@ fn push_output_block(
if streaming_tool_input {
pending_thinking.insert(block_index, (thinking, signature));
} else {
events.push(AssistantEvent::Thinking { thinking, signature });
events.push(AssistantEvent::Thinking {
thinking,
signature,
});
}
}
OutputContentBlock::RedactedThinking { .. } => {}
Expand Down Expand Up @@ -5983,8 +5988,7 @@ fn command_exists(command: &str) -> bool {
.arg("-lc")
.arg(format!("command -v {command} >/dev/null 2>&1"))
.status()
.map(|status| status.success())
.unwrap_or(false)
.is_ok_and(|status| status.success())
}

#[allow(clippy::too_many_lines)]
Expand Down