use std::{collections::BTreeMap, future::Future, pin::Pin};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use runifold_model::ContentPart;
use crate::{ToolContext, ToolDescriptor, ToolError};
#[cfg(not(target_arch = "wasm32"))]
pub type ToolFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
#[cfg(target_arch = "wasm32")]
pub type ToolFuture<'a, T> = Pin<Box<dyn Future<Output = T> + 'a>>;
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct ToolOutput {
pub content: Vec<ContentPart>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub structured_content: Option<Value>,
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub metadata: BTreeMap<String, Value>,
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
pub is_error: bool,
pub model_visible: bool,
}
impl ToolOutput {
pub fn model_visible(value: Value) -> Self {
let structured_content = Some(value.clone());
let text = match value {
Value::String(text) => text,
value => value.to_string(),
};
Self {
content: vec![ContentPart::text(text)],
structured_content,
metadata: BTreeMap::new(),
is_error: false,
model_visible: true,
}
}
pub fn rich(content: Vec<ContentPart>) -> Self {
Self {
content,
structured_content: None,
metadata: BTreeMap::new(),
is_error: false,
model_visible: true,
}
}
#[must_use]
pub fn with_structured_content(mut self, value: Value) -> Self {
self.structured_content = Some(value);
self
}
#[must_use]
pub fn with_metadata(mut self, key: impl Into<String>, value: Value) -> Self {
self.metadata.insert(key.into(), value);
self
}
pub fn host_only(content: Vec<ContentPart>) -> Self {
Self {
content,
structured_content: None,
metadata: BTreeMap::new(),
is_error: false,
model_visible: false,
}
}
pub fn model_error(content: Vec<ContentPart>) -> Self {
Self {
content,
structured_content: None,
metadata: BTreeMap::new(),
is_error: true,
model_visible: true,
}
}
}
pub trait Tool: Send + Sync {
fn descriptor(&self) -> &ToolDescriptor;
fn invoke(
&self,
input: Value,
context: ToolContext,
) -> ToolFuture<'_, Result<ToolOutput, ToolError>>;
}