mod ast_grep;
mod bash;
pub(super) mod common;
mod find;
mod grep;
mod hash_edit;
mod list_files;
mod magi_control;
mod read;
mod view_image;
mod web;
mod write;
use super::*;
use common::*;
use grep::{grep_bool, grep_usize};
pub(super) fn project_tool_card(input: &ToolCardInput<'_>) -> CardDraft {
let capability = ToolCapability::from_dispatch_name(input.tool_name);
let mut card = match capability {
Some(ToolCapability::ViewImage) => view_image::view_image_card(input),
Some(ToolCapability::Write) => write::write_card(input),
Some(ToolCapability::HashEdit) => hash_edit::hash_edit_card(input),
Some(ToolCapability::Read) => read::read_card(input),
Some(ToolCapability::Bash) if !input.bash_mode_response => bash::bash_card(input),
Some(ToolCapability::BashJob) => bash::job_card(input),
Some(ToolCapability::AstGrep) => ast_grep::ast_grep_card(input),
Some(ToolCapability::Grep) => grep::grep_card(input),
Some(ToolCapability::ListFiles) => list_files::list_files_card(input),
Some(ToolCapability::Find) => find::find_card(input),
Some(ToolCapability::Web) => web::web_card(input),
Some(ToolCapability::MagiControl) => magi_control::magi_control_card(input),
None if input.tool_name == crate::code_mode::TOOL_NAME => {
super::code_mode::project_code_mode_card(input)
}
_ => generic_tool_card(input),
};
if (capability.is_some() || input.tool_name == crate::code_mode::TOOL_NAME)
&& let Some(metadata) = prompt_injection_protection_metadata(input.detail)
{
card.metadata.push(metadata);
}
card
}
fn basic_card(role: ToolCardRole, title: impl Into<String>, body: &str) -> CardDraft {
CardDraft {
role,
title: title.into(),
status: CardStatus::None,
metadata: Vec::new(),
body: sanitize_display_text(body),
body_lines: Vec::new(),
activity_rows: Vec::new(),
}
}
fn generic_tool_card(input: &ToolCardInput<'_>) -> CardDraft {
let role =
if ToolCapability::from_dispatch_name(input.tool_name) == Some(ToolCapability::Subagents) {
ToolCardRole::SubagentBatch
} else {
ToolCardRole::Tool
};
let title = if input.bash_mode_response {
"Bash Mode Response"
} else if input.tool_name.trim().is_empty() {
"Tool"
} else {
input.tool_name
};
let body = if input.bash_mode_response {
bounded_preview_lines(input.preview)
} else if role == ToolCardRole::Tool {
"Detail unavailable for this tool".into()
} else {
String::new()
};
let mut card = basic_card(role, sanitized_single_line(title), &body);
card.status = input_status(input);
card
}