use anyhow::Result;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolDefinition {
pub name: String,
pub description: String,
pub parameters: serde_json::Value,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ToolCall {
pub id: String,
pub name: String,
pub arguments: serde_json::Value,
}
#[derive(Debug, Clone)]
pub struct LlmResponse {
pub text: String,
pub tool_calls: Vec<ToolCall>,
pub finish_reason: Option<String>,
pub input_tokens: usize,
pub output_tokens: usize,
}
#[derive(Debug, Clone)]
pub struct LlmMessage {
pub role: String,
pub text: String,
pub tool_calls: Vec<ToolCall>,
pub tool_call_id: Option<String>,
}
impl LlmMessage {
pub fn user(text: String) -> Self {
Self {
role: "user".into(),
text,
tool_calls: vec![],
tool_call_id: None,
}
}
pub fn assistant(text: String) -> Self {
Self {
role: "assistant".into(),
text,
tool_calls: vec![],
tool_call_id: None,
}
}
pub fn assistant_from(resp: &LlmResponse) -> Self {
Self {
role: "assistant".into(),
text: resp.text.clone(),
tool_calls: resp.tool_calls.clone(),
tool_call_id: None,
}
}
pub fn tool_result(call_id: &str, content: &str) -> Self {
Self {
role: "tool".into(),
text: content.into(),
tool_calls: vec![],
tool_call_id: Some(call_id.into()),
}
}
}
#[async_trait]
pub trait LlmProvider: Send + Sync {
async fn complete(
&self,
messages: Vec<LlmMessage>,
tools: Vec<ToolDefinition>,
model: &str,
temperature: Option<f32>,
) -> Result<LlmResponse>;
}
#[async_trait]
pub trait ToolCallRewriter: Send + Sync {
async fn maybe_reformat(
&self,
response: LlmResponse,
tools: &[ToolDefinition],
strict: bool,
) -> Result<LlmResponse>;
}
pub trait RlmEventBus: Send + Sync {
fn emit_progress(&self, event: crate::RlmProgressEvent);
fn emit_completion(&self, event: crate::RlmCompletion);
}