chore: use a Conversation type (#3735)

This commit is contained in:
Jack Amadeo
2025-08-06 22:06:13 -04:00
committed by GitHub
parent 17ea675def
commit 5eb01004a4
90 changed files with 994 additions and 790 deletions
+1 -1
View File
@@ -15,8 +15,8 @@ use super::formats::anthropic::{
create_request, get_usage, response_to_message, response_to_streaming_message,
};
use super::utils::{emit_debug_trace, get_model, map_http_error_to_provider_error};
use crate::conversation::message::Message;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use crate::providers::retry::ProviderRetry;
use rmcp::model::Tool;
+1 -1
View File
@@ -10,8 +10,8 @@ use super::errors::ProviderError;
use super::formats::openai::{create_request, get_usage, response_to_message};
use super::retry::ProviderRetry;
use super::utils::{emit_debug_trace, get_model, handle_response_openai_compat, ImageFormat};
use crate::conversation::message::Message;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use rmcp::model::Tool;
+7 -3
View File
@@ -4,7 +4,8 @@ use serde::{Deserialize, Serialize};
use super::errors::ProviderError;
use super::retry::RetryConfig;
use crate::message::Message;
use crate::conversation::message::Message;
use crate::conversation::Conversation;
use crate::model::ModelConfig;
use crate::utils::safe_truncate;
use rmcp::model::Tool;
@@ -370,7 +371,7 @@ pub trait Provider: Send + Sync {
}
/// Returns the first 3 user messages as strings for session naming
fn get_initial_user_messages(&self, messages: &[Message]) -> Vec<String> {
fn get_initial_user_messages(&self, messages: &Conversation) -> Vec<String> {
messages
.iter()
.filter(|m| m.role == rmcp::model::Role::User)
@@ -381,7 +382,10 @@ pub trait Provider: Send + Sync {
/// Generate a session name/description based on the conversation history
/// Creates a prompt asking for a concise description in 4 words or less.
async fn generate_session_name(&self, messages: &[Message]) -> Result<String, ProviderError> {
async fn generate_session_name(
&self,
messages: &Conversation,
) -> Result<String, ProviderError> {
let context = self.get_initial_user_messages(messages);
let prompt = self.create_session_name_prompt(&context);
let message = Message::user().with_text(&prompt);
+1 -1
View File
@@ -3,8 +3,8 @@ use std::collections::HashMap;
use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage};
use super::errors::ProviderError;
use super::retry::ProviderRetry;
use crate::conversation::message::Message;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use crate::providers::utils::emit_debug_trace;
use anyhow::Result;
+1 -1
View File
@@ -11,8 +11,8 @@ use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage};
use super::errors::ProviderError;
use super::utils::emit_debug_trace;
use crate::config::Config;
use crate::conversation::message::{Message, MessageContent};
use crate::impl_provider_default;
use crate::message::{Message, MessageContent};
use crate::model::ModelConfig;
use rmcp::model::Tool;
+1 -1
View File
@@ -18,8 +18,8 @@ use super::oauth;
use super::retry::ProviderRetry;
use super::utils::{get_model, handle_response_openai_compat, ImageFormat};
use crate::config::ConfigError;
use crate::conversation::message::Message;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use crate::providers::formats::openai::{get_usage, response_to_streaming_message};
use crate::providers::retry::{
+1 -1
View File
@@ -174,7 +174,7 @@ fn create_provider(name: &str, model: ModelConfig) -> Result<Arc<dyn Provider>>
#[cfg(test)]
mod tests {
use super::*;
use crate::message::{Message, MessageContent};
use crate::conversation::message::{Message, MessageContent};
use crate::providers::base::{ProviderMetadata, ProviderUsage, Usage};
use chrono::Utc;
use rmcp::model::{AnnotateAble, RawTextContent, Role};
@@ -1,4 +1,4 @@
use crate::message::{Message, MessageContent};
use crate::conversation::message::{Message, MessageContent};
use crate::model::ModelConfig;
use crate::providers::base::Usage;
use crate::providers::errors::ProviderError;
@@ -676,6 +676,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
use crate::conversation::message::Message;
use rmcp::object;
use serde_json::json;
@@ -983,6 +984,7 @@ mod tests {
#[test]
fn test_tool_error_handling_maintains_pairing() {
use crate::conversation::message::Message;
use mcp_core::handler::ToolError;
let messages = vec![
@@ -11,7 +11,7 @@ use rmcp::model::{Content, RawContent, ResourceContents, Role, Tool};
use serde_json::Value;
use super::super::base::Usage;
use crate::message::{Message, MessageContent};
use crate::conversation::message::{Message, MessageContent};
pub fn to_bedrock_message(message: &Message) -> Result<bedrock::Message> {
bedrock::Message::builder()
@@ -1,4 +1,4 @@
use crate::message::{Message, MessageContent};
use crate::conversation::message::{Message, MessageContent};
use crate::model::ModelConfig;
use crate::providers::utils::{
convert_image, detect_image_path, is_valid_function_name, load_image_file, safely_parse_json,
@@ -9,6 +9,7 @@ use mcp_core::{ToolCall, ToolError};
use rmcp::model::{AnnotateAble, Content, RawContent, ResourceContents, Role, Tool};
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
#[derive(Serialize)]
struct DatabricksMessage {
content: Value,
@@ -616,6 +617,7 @@ pub fn create_request(
#[cfg(test)]
mod tests {
use super::*;
use crate::conversation::message::Message;
use rmcp::object;
use serde_json::json;
@@ -1,5 +1,5 @@
use super::{anthropic, google};
use crate::message::Message;
use crate::conversation::message::Message;
use crate::model::ModelConfig;
use crate::providers::base::Usage;
use anyhow::{Context, Result};
+2 -1
View File
@@ -1,4 +1,3 @@
use crate::message::{Message, MessageContent};
use crate::model::ModelConfig;
use crate::providers::base::Usage;
use crate::providers::errors::ProviderError;
@@ -8,6 +7,7 @@ use mcp_core::tool::ToolCall;
use rand::{distributions::Alphanumeric, Rng};
use rmcp::model::{AnnotateAble, RawContent, Role, Tool};
use crate::conversation::message::{Message, MessageContent};
use serde_json::{json, Map, Value};
use std::ops::Deref;
@@ -335,6 +335,7 @@ pub fn create_request(
#[cfg(test)]
mod tests {
use super::*;
use crate::conversation::message::Message;
use rmcp::{model::Content, object};
use serde_json::json;
+2 -1
View File
@@ -1,4 +1,4 @@
use crate::message::{Message, MessageContent};
use crate::conversation::message::{Message, MessageContent};
use crate::model::ModelConfig;
use crate::providers::base::{ProviderUsage, Usage};
use crate::providers::utils::{
@@ -641,6 +641,7 @@ pub fn create_request(
#[cfg(test)]
mod tests {
use super::*;
use crate::conversation::message::Message;
use rmcp::object;
use serde_json::json;
use tokio::pin;
@@ -1,4 +1,4 @@
use crate::message::{Message, MessageContent};
use crate::conversation::message::{Message, MessageContent};
use crate::model::ModelConfig;
use crate::providers::base::Usage;
use crate::providers::errors::ProviderError;
@@ -359,6 +359,7 @@ pub fn create_request(
#[cfg(test)]
mod tests {
use super::*;
use crate::conversation::message::Message;
use rmcp::object;
use serde_json::json;
@@ -546,6 +547,7 @@ data: {"id":"a9537c2c-2017-4906-9817-2456168d89fa","model":"claude-3-5-sonnet","
#[test]
fn test_create_request_format() -> Result<()> {
use crate::conversation::message::Message;
use crate::model::ModelConfig;
let model_config = ModelConfig::new_or_fail("claude-3-5-sonnet");
@@ -654,6 +656,7 @@ data: {"id":"a9537c2c-2017-4906-9817-2456168d89fa","model":"claude-3-5-sonnet","
#[test]
fn test_create_request_excludes_tools_for_description() -> Result<()> {
use crate::conversation::message::Message;
use crate::model::ModelConfig;
let model_config = ModelConfig::new_or_fail("claude-3-5-sonnet");
@@ -675,6 +678,7 @@ data: {"id":"a9537c2c-2017-4906-9817-2456168d89fa","model":"claude-3-5-sonnet","
#[test]
fn test_message_formatting_skips_tool_requests() {
use crate::conversation::message::Message;
use mcp_core::tool::ToolCall;
// Create a conversation with text, tool requests, and tool responses
+1 -1
View File
@@ -8,7 +8,7 @@ use serde_json::Value;
use tokio::time::sleep;
use url::Url;
use crate::message::Message;
use crate::conversation::message::Message;
use crate::model::ModelConfig;
use crate::providers::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage};
+1 -1
View File
@@ -9,8 +9,8 @@ use tokio::process::Command;
use super::base::{Provider, ProviderMetadata, ProviderUsage, Usage};
use super::errors::ProviderError;
use super::utils::emit_debug_trace;
use crate::conversation::message::{Message, MessageContent};
use crate::impl_provider_default;
use crate::message::{Message, MessageContent};
use crate::model::ModelConfig;
use rmcp::model::Role;
use rmcp::model::Tool;
+1 -1
View File
@@ -18,8 +18,8 @@ use super::retry::ProviderRetry;
use super::utils::{emit_debug_trace, get_model, handle_response_openai_compat, ImageFormat};
use crate::config::{Config, ConfigError};
use crate::conversation::message::Message;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use crate::providers::base::ConfigKey;
use rmcp::model::Tool;
+1 -1
View File
@@ -2,8 +2,8 @@ use super::api_client::{ApiClient, AuthMethod};
use super::errors::ProviderError;
use super::retry::ProviderRetry;
use super::utils::{emit_debug_trace, handle_response_google_compat, unescape_json_values};
use crate::conversation::message::Message;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use crate::providers::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage};
use crate::providers::formats::google::{create_request, get_usage, response_to_message};
+1 -1
View File
@@ -2,8 +2,8 @@ use super::api_client::{ApiClient, AuthMethod};
use super::errors::ProviderError;
use super::retry::ProviderRetry;
use super::utils::{get_model, handle_response_openai_compat};
use crate::conversation::message::Message;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use crate::providers::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage};
use crate::providers::formats::openai::{create_request, get_usage, response_to_message};
+2 -2
View File
@@ -6,7 +6,7 @@ use tokio::sync::Mutex;
use super::base::{LeadWorkerProviderTrait, Provider, ProviderMetadata, ProviderUsage};
use super::errors::ProviderError;
use crate::message::{Message, MessageContent};
use crate::conversation::message::{Message, MessageContent};
use crate::model::ModelConfig;
use rmcp::model::Tool;
use rmcp::model::{Content, RawContent};
@@ -454,7 +454,7 @@ impl Provider for LeadWorkerProvider {
#[cfg(test)]
mod tests {
use super::*;
use crate::message::MessageContent;
use crate::conversation::message::{Message, MessageContent};
use crate::providers::base::{ProviderMetadata, ProviderUsage, Usage};
use chrono::Utc;
use rmcp::model::{AnnotateAble, RawTextContent, Role};
+1 -1
View File
@@ -9,8 +9,8 @@ use super::embedding::EmbeddingCapable;
use super::errors::ProviderError;
use super::retry::ProviderRetry;
use super::utils::{emit_debug_trace, get_model, handle_response_openai_compat, ImageFormat};
use crate::conversation::message::Message;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use rmcp::model::Tool;
+6 -2
View File
@@ -3,8 +3,9 @@ use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage};
use super::errors::ProviderError;
use super::retry::ProviderRetry;
use super::utils::{get_model, handle_response_openai_compat};
use crate::conversation::message::Message;
use crate::conversation::Conversation;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use crate::providers::formats::openai::{create_request, get_usage, response_to_message};
use crate::utils::safe_truncate;
@@ -159,7 +160,10 @@ impl Provider for OllamaProvider {
/// Generate a session name based on the conversation history
/// This override filters out reasoning tokens that some Ollama models produce
async fn generate_session_name(&self, messages: &[Message]) -> Result<String, ProviderError> {
async fn generate_session_name(
&self,
messages: &Conversation,
) -> Result<String, ProviderError> {
let context = self.get_initial_user_messages(messages);
let message = Message::user().with_text(self.create_session_name_prompt(&context));
let result = self
+1 -1
View File
@@ -20,8 +20,8 @@ use super::utils::{
emit_debug_trace, get_model, handle_response_openai_compat, handle_status_openai_compat,
ImageFormat,
};
use crate::conversation::message::Message;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use crate::providers::base::MessageStream;
use crate::providers::formats::openai::response_to_streaming_message;
+1 -1
View File
@@ -10,8 +10,8 @@ use super::utils::{
emit_debug_trace, get_model, handle_response_google_compat, handle_response_openai_compat,
is_google_model,
};
use crate::conversation::message::Message;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use crate::providers::formats::openai::{create_request, get_usage, response_to_message};
use rmcp::model::Tool;
+1 -1
View File
@@ -13,8 +13,8 @@ use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage};
use super::errors::ProviderError;
use super::retry::ProviderRetry;
use super::utils::emit_debug_trace;
use crate::conversation::message::{Message, MessageContent};
use crate::impl_provider_default;
use crate::message::{Message, MessageContent};
use crate::model::ModelConfig;
use chrono::Utc;
use rmcp::model::Role;
+1 -1
View File
@@ -10,8 +10,8 @@ use super::formats::snowflake::{create_request, get_usage, response_to_message};
use super::retry::ProviderRetry;
use super::utils::{get_model, map_http_error_to_provider_error, ImageFormat};
use crate::config::ConfigError;
use crate::conversation::message::Message;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use rmcp::model::Tool;
+2 -2
View File
@@ -9,7 +9,7 @@ use std::sync::{Arc, Mutex};
use super::base::{Provider, ProviderMetadata, ProviderUsage};
use super::errors::ProviderError;
use crate::message::Message;
use crate::conversation::message::Message;
use crate::model::ModelConfig;
use rmcp::model::Tool;
@@ -162,7 +162,7 @@ impl Provider for TestProvider {
#[cfg(test)]
mod tests {
use super::*;
use crate::message::{Message, MessageContent};
use crate::conversation::message::{Message, MessageContent};
use crate::providers::base::{ProviderUsage, Usage};
use chrono::Utc;
use rmcp::model::{RawTextContent, Role, TextContent};
+7 -4
View File
@@ -33,7 +33,8 @@
use super::errors::ProviderError;
use super::ollama::OLLAMA_DEFAULT_PORT;
use super::ollama::OLLAMA_HOST;
use crate::message::{Message, MessageContent};
use crate::conversation::message::{Message, MessageContent};
use crate::conversation::Conversation;
use crate::model::ModelConfig;
use crate::providers::formats::openai::create_request;
use anyhow::Result;
@@ -310,8 +311,8 @@ pub fn format_tool_info(tools: &[Tool]) -> String {
/// Convert messages containing ToolRequest/ToolResponse to text messages for toolshim mode
/// This is necessary because some providers (like Bedrock) validate that tool_use/tool_result
/// blocks can only exist when tools are defined, but in toolshim mode we pass empty tools
pub fn convert_tool_messages_to_text(messages: &[Message]) -> Vec<Message> {
messages
pub fn convert_tool_messages_to_text(messages: &[Message]) -> Conversation {
let converted_messages: Vec<Message> = messages
.iter()
.map(|message| {
let mut new_content = Vec::new();
@@ -366,7 +367,9 @@ pub fn convert_tool_messages_to_text(messages: &[Message]) -> Vec<Message> {
message.clone()
}
})
.collect()
.collect();
Conversation::new_unvalidated(converted_messages)
}
/// Modifies the system prompt to include tool usage instructions when tool interpretation is enabled
+1 -1
View File
@@ -9,8 +9,8 @@ use super::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage};
use super::errors::ProviderError;
use super::retry::ProviderRetry;
use super::utils::map_http_error_to_provider_error;
use crate::conversation::message::{Message, MessageContent};
use crate::impl_provider_default;
use crate::message::{Message, MessageContent};
use crate::model::ModelConfig;
use mcp_core::{ToolCall, ToolResult};
use rmcp::model::{Role, Tool};
+1 -1
View File
@@ -2,8 +2,8 @@ use super::api_client::{ApiClient, AuthMethod};
use super::errors::ProviderError;
use super::retry::ProviderRetry;
use super::utils::{get_model, handle_response_openai_compat};
use crate::conversation::message::Message;
use crate::impl_provider_default;
use crate::message::Message;
use crate::model::ModelConfig;
use crate::providers::base::{ConfigKey, Provider, ProviderMetadata, ProviderUsage, Usage};
use crate::providers::formats::openai::{create_request, get_usage, response_to_message};