use super::sql_format::{collapse_whitespace, format_sql};
pub(crate) fn tool_call_detail(name: &str, arguments: &serde_json::Value) -> Option<String> {
match name {
"workspace_write" | "workspace_edit" => {
let path = arguments
.get("path")
.and_then(serde_json::Value::as_str)
.filter(|value| !value.is_empty())?;
Some(path.to_owned())
}
"run_command" => {
let program = arguments
.get("program")
.and_then(serde_json::Value::as_str)
.filter(|value| !value.is_empty())?;
Some(program.to_owned())
}
"bounded_sql_query"
| "bounded_sql_query_all"
| "render_chart"
| "result_shape"
| "column_health"
| "join_check" => {
let sql = arguments.get("sql").and_then(serde_json::Value::as_str)?;
let sql = collapse_whitespace(sql);
if sql.is_empty() {
return None;
}
let connection = arguments
.get("connection")
.and_then(serde_json::Value::as_str)
.filter(|value| !value.is_empty());
Some(match (name, connection) {
("render_chart", connection) => {
let chart_type = arguments
.get("chart_type")
.and_then(serde_json::Value::as_str)
.filter(|v| !v.is_empty());
match (connection, chart_type) {
(Some(conn), Some(ct)) => format!("{sql} (@{conn}) (chart: {ct})"),
(Some(conn), None) => format!("{sql} (@{conn})"),
(None, Some(ct)) => format!("{sql} (chart: {ct})"),
(None, None) => sql,
}
}
(_, Some(connection)) => format!("{sql} (@{connection})"),
("bounded_sql_query_all", None) => format!("{sql} (all connected databases)"),
_ => sql,
})
}
_ => None,
}
}
pub(crate) struct SqlCall {
pub(crate) target: Option<String>,
pub(crate) sql: String,
}
pub(crate) fn sql_tool_call(name: &str, arguments: &serde_json::Value) -> Option<SqlCall> {
match name {
"bounded_sql_query"
| "bounded_sql_query_all"
| "render_chart"
| "result_shape"
| "column_health"
| "join_check" => {
let raw = arguments.get("sql").and_then(serde_json::Value::as_str)?;
let sql = format_sql(raw);
if sql.is_empty() {
return None;
}
let connection = arguments
.get("connection")
.and_then(serde_json::Value::as_str)
.filter(|value| !value.is_empty());
let target = match (name, connection) {
(_, Some(connection)) => Some(format!("@{connection}")),
("bounded_sql_query_all", None) => Some("all connected databases".to_string()),
_ => None,
};
Some(SqlCall { target, sql })
}
_ => None,
}
}
#[cfg(test)]
mod c0_property_tests {
use super::tool_call_detail;
#[test]
fn workspace_write_completion_names_the_file_it_wrote() {
let detail = tool_call_detail(
"workspace_write",
&serde_json::json!({"path": "notes.md", "content": "hi"}),
)
.expect("workspace_write detail exists");
assert!(
detail.contains("notes.md"),
"workspace_write completion must name the file: got {detail:?}"
);
}
#[test]
fn run_command_request_names_the_program() {
let detail = tool_call_detail(
"run_command",
&serde_json::json!({"program": "pytest", "args": ["-q"]}),
)
.expect("run_command detail exists");
assert!(
detail.contains("pytest"),
"run_command request must name the program: got {detail:?}"
);
}
#[test]
fn both_adapters_render_the_same_fact_for_the_same_call() {
use crate::stream_render::terminal_event;
let arguments = serde_json::json!({"path": "notes.md", "content": "hi"});
let piped = terminal_event(saya_agent::AgentEvent::tool_requested(
"workspace_write",
arguments,
Some(saya_agent::ToolEffect {
database_data: false,
external_side_effect: false,
requires_approval: false,
local_state: saya_agent::LocalStateEffect::WriteWorkspace,
}),
))
.expect("a ToolRequested renders headlessly");
match piped {
crate::TerminalEvent::ToolRequested { detail, .. } => {
let detail = detail.expect("workspace_write exposes a detail");
assert!(
detail.contains("notes.md"),
"the shared seam must name the file: {detail:?}"
);
assert_eq!(
detail,
tool_call_detail(
"workspace_write",
&serde_json::json!({"path": "notes.md", "content": "hi"}),
)
.expect("same seam, same fact"),
"both adapters read the same seam, so the fact cannot drift"
);
}
other => panic!("a ToolRequested must map to ToolRequested: {other:?}"),
}
}
#[test]
fn an_uncovered_tool_keeps_todays_text_byte_exact() {
assert_eq!(
tool_call_detail("workspace_list", &serde_json::json!({"path": "notes"})),
None,
"workspace_list must keep today's None detail"
);
assert_eq!(
tool_call_detail("schema_discovery", &serde_json::json!({})),
None,
"schema_discovery must keep today's None detail"
);
}
#[test]
fn request_detail_never_carries_values_beyond_the_key_fact() {
let write = tool_call_detail(
"workspace_write",
&serde_json::json!({"path": "notes.md", "content": "SECRET-BODY"}),
)
.expect("workspace_write detail exists");
assert!(
!write.contains("SECRET-BODY"),
"file content must not reach the line: {write:?}"
);
let run = tool_call_detail(
"run_command",
&serde_json::json!({"program": "pytest", "args": ["--token", "SECRET-ARG"]}),
)
.expect("run_command detail exists");
assert_eq!(
run, "pytest",
"the request detail names the program only: {run:?}"
);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn render_chart_tool_call_detail_surfaces_sql() {
let detail = tool_call_detail(
"render_chart",
&serde_json::json!({"sql": "SELECT 1", "chart_type": "bar"}),
)
.expect("render_chart detail exists");
assert!(detail.contains("SELECT 1"));
assert!(detail.contains("(chart: bar)"));
}
#[test]
fn render_chart_sql_tool_call_surfaces_sql() {
let call = sql_tool_call(
"render_chart",
&serde_json::json!({"sql": "SELECT 1", "chart_type": "bar"}),
)
.expect("render_chart SqlCall exists");
assert_eq!(call.target, None);
assert_eq!(call.sql, "SELECT 1");
}
}