use crate::engine::message::{ToolCall, ToolResultData};
use serde_json::Value;
#[must_use]
pub fn part_text(part: &Value) -> Option<&str> {
part["text"]
.as_str()
.or_else(|| part["input_text"].as_str())
.or_else(|| part["output_text"].as_str())
}
#[must_use]
pub fn extract_text(content: Option<&Value>) -> String {
match content {
Some(Value::Array(parts)) => parts
.iter()
.filter_map(part_text)
.map(str::to_string)
.collect::<Vec<_>>()
.join("\n"),
Some(Value::String(text)) => text.clone(),
_ => String::new(),
}
}
#[must_use]
pub fn parse_tool_arguments(raw: &Value) -> Value {
if let Some(text) = raw.as_str()
&& let Ok(parsed) = serde_json::from_str::<Value>(text)
{
return parsed;
}
raw.clone()
}
#[must_use]
pub fn build_tool_call(
id: impl Into<String>,
name: impl Into<String>,
arguments: Option<&Value>,
) -> ToolCall {
let arguments = arguments.map_or(Value::Null, parse_tool_arguments);
ToolCall {
id: id.into(),
name: name.into(),
arguments,
}
}
#[must_use]
pub fn build_tool_result(
call_id: impl Into<String>,
fallback_name: impl Into<String>,
content_text: impl Into<String>,
is_error: bool,
) -> ToolResultData {
ToolResultData {
call_id: call_id.into(),
tool_name: fallback_name.into(),
content: content_text.into(),
is_error,
}
}