use futures_util::future::BoxFuture;
use gemini_live::types::{FunctionCallRequest, FunctionResponse, Tool};
#[derive(Debug, thiserror::Error)]
pub enum ToolExecutionError {
#[error("unsupported function `{name}`")]
UnsupportedFunction { name: String },
#[error("tool execution failed: {message}")]
Failed { message: String },
#[error("tool call `{call_id}` was cancelled")]
Cancelled { call_id: String },
}
impl ToolExecutionError {
pub fn unsupported_function(name: impl Into<String>) -> Self {
Self::UnsupportedFunction { name: name.into() }
}
pub fn failed(message: impl Into<String>) -> Self {
Self::Failed {
message: message.into(),
}
}
pub fn cancelled(call_id: impl Into<String>) -> Self {
Self::Cancelled {
call_id: call_id.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ToolDescriptor {
pub key: String,
pub summary: String,
pub kind: ToolKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ToolKind {
BuiltIn,
Local,
Remote,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct ToolCapability {
pub can_continue_async_after_timeout: bool,
}
impl ToolCapability {
pub const INLINE_ONLY: Self = Self {
can_continue_async_after_timeout: false,
};
pub const BACKGROUND_CONTINUABLE: Self = Self {
can_continue_async_after_timeout: true,
};
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ToolSpecification {
pub function_name: String,
pub capability: ToolCapability,
}
impl ToolSpecification {
pub fn new(function_name: impl Into<String>, capability: ToolCapability) -> Self {
Self {
function_name: function_name.into(),
capability,
}
}
}
pub trait ToolProvider: Send + Sync + 'static {
fn advertised_tools(&self) -> Option<Vec<Tool>> {
None
}
fn descriptors(&self) -> Vec<ToolDescriptor> {
Vec::new()
}
fn specifications(&self) -> Vec<ToolSpecification> {
Vec::new()
}
}
pub trait ToolExecutor: Send + Sync + 'static {
fn execute<'a>(
&'a self,
call: FunctionCallRequest,
) -> BoxFuture<'a, Result<FunctionResponse, ToolExecutionError>>;
fn cancel(&self, _call_id: &str) -> bool {
false
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct NoopToolSource;
impl ToolProvider for NoopToolSource {}
impl ToolExecutor for NoopToolSource {
fn execute<'a>(
&'a self,
call: FunctionCallRequest,
) -> BoxFuture<'a, Result<FunctionResponse, ToolExecutionError>> {
Box::pin(async move { Err(ToolExecutionError::unsupported_function(call.name)) })
}
}