@@ -149,7 +149,7 @@ impl CursorAgentProvider {
|
||||
MessageContent::ToolRequest(tool_request) => {
|
||||
if let Ok(tool_call) = &tool_request.tool_call {
|
||||
full_prompt.push_str(&format!(
|
||||
"Tool Use: {} with args: {:?}\n",
|
||||
"Tool Use: {} with args: {}\n",
|
||||
tool_call.name, tool_call.arguments
|
||||
));
|
||||
}
|
||||
|
||||
@@ -3,7 +3,8 @@ use crate::model::ModelConfig;
|
||||
use crate::providers::base::Usage;
|
||||
use crate::providers::errors::ProviderError;
|
||||
use anyhow::{anyhow, Result};
|
||||
use rmcp::model::{object, CallToolRequestParam, ErrorCode, ErrorData, Role, Tool};
|
||||
use mcp_core::ToolCall;
|
||||
use rmcp::model::{ErrorCode, ErrorData, Role, Tool};
|
||||
use serde_json::{json, Value};
|
||||
use std::collections::HashSet;
|
||||
|
||||
@@ -229,24 +230,19 @@ pub fn response_to_message(response: &Value) -> Result<Message> {
|
||||
let name = block
|
||||
.get(NAME_FIELD)
|
||||
.and_then(|n| n.as_str())
|
||||
.ok_or_else(|| anyhow!("Missing tool_use name"))?
|
||||
.to_string();
|
||||
.ok_or_else(|| anyhow!("Missing tool_use name"))?;
|
||||
let input = block
|
||||
.get(INPUT_FIELD)
|
||||
.ok_or_else(|| anyhow!("Missing tool_use input"))?;
|
||||
|
||||
let tool_call = CallToolRequestParam {
|
||||
name: name.into(),
|
||||
arguments: Some(object(input.clone())),
|
||||
};
|
||||
let tool_call = ToolCall::new(name, input.clone());
|
||||
message = message.with_tool_request(id, Ok(tool_call));
|
||||
}
|
||||
Some(THINKING_TYPE) => {
|
||||
let thinking = block
|
||||
.get(THINKING_TYPE)
|
||||
.and_then(|t| t.as_str())
|
||||
.ok_or_else(|| anyhow!("Missing thinking content"))?
|
||||
.to_string();
|
||||
.ok_or_else(|| anyhow!("Missing thinking content"))?;
|
||||
let signature = block
|
||||
.get(SIGNATURE_FIELD)
|
||||
.and_then(|s| s.as_str())
|
||||
@@ -593,8 +589,7 @@ where
|
||||
}
|
||||
};
|
||||
|
||||
let tool_call = CallToolRequestParam{ name: name.into(), arguments: Some(object(parsed_args)) };
|
||||
|
||||
let tool_call = ToolCall::new(&name, parsed_args);
|
||||
let mut message = Message::new(
|
||||
rmcp::model::Role::Assistant,
|
||||
chrono::Utc::now().timestamp(),
|
||||
@@ -755,7 +750,7 @@ mod tests {
|
||||
if let MessageContent::ToolRequest(tool_request) = &message.content[0] {
|
||||
let tool_call = tool_request.tool_call.as_ref().unwrap();
|
||||
assert_eq!(tool_call.name, "calculator");
|
||||
assert_eq!(tool_call.arguments, Some(object!({"expression": "2 + 2"})));
|
||||
assert_eq!(tool_call.arguments, json!({"expression": "2 + 2"}));
|
||||
} else {
|
||||
panic!("Expected ToolRequest content");
|
||||
}
|
||||
@@ -997,10 +992,7 @@ mod tests {
|
||||
let messages = vec![
|
||||
Message::assistant().with_tool_request(
|
||||
"tool_1",
|
||||
Ok(CallToolRequestParam {
|
||||
name: "calculator".into(),
|
||||
arguments: Some(object!({"expression": "2 + 2"})),
|
||||
}),
|
||||
Ok(ToolCall::new("calculator", json!({"expression": "2 + 2"}))),
|
||||
),
|
||||
Message::user().with_tool_response(
|
||||
"tool_1",
|
||||
|
||||
@@ -2,16 +2,13 @@ use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::mcp_utils::ToolResult;
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use aws_sdk_bedrockruntime::types as bedrock;
|
||||
use aws_smithy_types::{Document, Number};
|
||||
use base64::Engine;
|
||||
use chrono::Utc;
|
||||
use rmcp::model::{
|
||||
object, CallToolRequestParam, Content, ErrorCode, ErrorData, RawContent, ResourceContents,
|
||||
Role, Tool,
|
||||
};
|
||||
use mcp_core::{ToolCall, ToolResult};
|
||||
use rmcp::model::{Content, ErrorCode, ErrorData, RawContent, ResourceContents, Role, Tool};
|
||||
use serde_json::Value;
|
||||
|
||||
use super::super::base::Usage;
|
||||
@@ -60,7 +57,7 @@ pub fn to_bedrock_message_content(content: &MessageContent) -> Result<bedrock::C
|
||||
bedrock::ToolUseBlock::builder()
|
||||
.tool_use_id(tool_use_id)
|
||||
.name(call.name.to_string())
|
||||
.input(to_bedrock_json(&Value::from(call.arguments.clone())))
|
||||
.input(to_bedrock_json(&call.arguments))
|
||||
.build()
|
||||
} else {
|
||||
bedrock::ToolUseBlock::builder()
|
||||
@@ -75,7 +72,7 @@ pub fn to_bedrock_message_content(content: &MessageContent) -> Result<bedrock::C
|
||||
bedrock::ToolUseBlock::builder()
|
||||
.tool_use_id(tool_use_id)
|
||||
.name(call.name.to_string())
|
||||
.input(to_bedrock_json(&Value::from(call.arguments.clone())))
|
||||
.input(to_bedrock_json(&call.arguments))
|
||||
.build()
|
||||
} else {
|
||||
bedrock::ToolUseBlock::builder()
|
||||
@@ -285,10 +282,10 @@ pub fn from_bedrock_content_block(block: &bedrock::ContentBlock) -> Result<Messa
|
||||
bedrock::ContentBlock::Text(text) => MessageContent::text(text),
|
||||
bedrock::ContentBlock::ToolUse(tool_use) => MessageContent::tool_request(
|
||||
tool_use.tool_use_id.to_string(),
|
||||
Ok(CallToolRequestParam {
|
||||
name: tool_use.name.clone().into(),
|
||||
arguments: Some(object(from_bedrock_json(&tool_use.input.clone())?)),
|
||||
}),
|
||||
Ok(ToolCall::new(
|
||||
tool_use.name.to_string(),
|
||||
from_bedrock_json(&tool_use.input)?,
|
||||
)),
|
||||
),
|
||||
bedrock::ContentBlock::ToolResult(tool_res) => MessageContent::tool_response(
|
||||
tool_res.tool_use_id.to_string(),
|
||||
|
||||
@@ -5,9 +5,9 @@ use crate::providers::utils::{
|
||||
sanitize_function_name, ImageFormat,
|
||||
};
|
||||
use anyhow::{anyhow, Error};
|
||||
use mcp_core::ToolCall;
|
||||
use rmcp::model::{
|
||||
object, AnnotateAble, CallToolRequestParam, Content, ErrorCode, ErrorData, RawContent,
|
||||
ResourceContents, Role, Tool,
|
||||
AnnotateAble, Content, ErrorCode, ErrorData, RawContent, ResourceContents, Role, Tool,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
@@ -109,7 +109,7 @@ fn format_messages(messages: &[Message], image_format: &ImageFormat) -> Vec<Data
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": sanitized_name,
|
||||
"arguments": tool_call.arguments,
|
||||
"arguments": tool_call.arguments.to_string(),
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -286,7 +286,6 @@ pub fn format_tools(tools: &[Tool]) -> anyhow::Result<Vec<Value>> {
|
||||
}
|
||||
|
||||
/// Convert Databricks' API response to internal Message format
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub fn response_to_message(response: &Value) -> anyhow::Result<Message> {
|
||||
let original = &response["choices"][0]["message"];
|
||||
let mut content = Vec::new();
|
||||
@@ -374,10 +373,7 @@ pub fn response_to_message(response: &Value) -> anyhow::Result<Message> {
|
||||
Ok(params) => {
|
||||
content.push(MessageContent::tool_request(
|
||||
id,
|
||||
Ok(CallToolRequestParam {
|
||||
name: function_name.into(),
|
||||
arguments: Some(object(params)),
|
||||
}),
|
||||
Ok(ToolCall::new(&function_name, params)),
|
||||
));
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -775,10 +771,7 @@ mod tests {
|
||||
Message::user().with_text("How are you?"),
|
||||
Message::assistant().with_tool_request(
|
||||
"tool1",
|
||||
Ok(CallToolRequestParam {
|
||||
name: "example".into(),
|
||||
arguments: Some(object!({"param1": "value1"})),
|
||||
}),
|
||||
Ok(ToolCall::new("example", json!({"param1": "value1"}))),
|
||||
),
|
||||
];
|
||||
|
||||
@@ -814,10 +807,7 @@ mod tests {
|
||||
fn test_format_messages_multiple_content() -> anyhow::Result<()> {
|
||||
let mut messages = vec![Message::assistant().with_tool_request(
|
||||
"tool1",
|
||||
Ok(CallToolRequestParam {
|
||||
name: "example".into(),
|
||||
arguments: Some(object!({"param1": "value1"})),
|
||||
}),
|
||||
Ok(ToolCall::new("example", json!({"param1": "value1"}))),
|
||||
)];
|
||||
|
||||
// Get the ID from the tool request to use in the response
|
||||
@@ -966,7 +956,7 @@ mod tests {
|
||||
if let MessageContent::ToolRequest(request) = &message.content[0] {
|
||||
let tool_call = request.tool_call.as_ref().unwrap();
|
||||
assert_eq!(tool_call.name, "example_fn");
|
||||
assert_eq!(tool_call.arguments, Some(object!({"param": "value"})));
|
||||
assert_eq!(tool_call.arguments, json!({"param": "value"}));
|
||||
} else {
|
||||
panic!("Expected ToolRequest content");
|
||||
}
|
||||
@@ -1037,7 +1027,7 @@ mod tests {
|
||||
if let MessageContent::ToolRequest(request) = &message.content[0] {
|
||||
let tool_call = request.tool_call.as_ref().unwrap();
|
||||
assert_eq!(tool_call.name, "example_fn");
|
||||
assert_eq!(tool_call.arguments, Some(object!({})));
|
||||
assert_eq!(tool_call.arguments, json!({}));
|
||||
} else {
|
||||
panic!("Expected ToolRequest content");
|
||||
}
|
||||
|
||||
@@ -3,10 +3,9 @@ use crate::providers::base::Usage;
|
||||
use crate::providers::errors::ProviderError;
|
||||
use crate::providers::utils::{is_valid_function_name, sanitize_function_name};
|
||||
use anyhow::Result;
|
||||
use mcp_core::ToolCall;
|
||||
use rand::{distributions::Alphanumeric, Rng};
|
||||
use rmcp::model::{
|
||||
object, AnnotateAble, CallToolRequestParam, ErrorCode, ErrorData, RawContent, Role, Tool,
|
||||
};
|
||||
use rmcp::model::{AnnotateAble, ErrorCode, ErrorData, RawContent, Role, Tool};
|
||||
use std::borrow::Cow;
|
||||
|
||||
use crate::conversation::message::{Message, MessageContent};
|
||||
@@ -44,14 +43,12 @@ pub fn format_messages(messages: &[Message]) -> Vec<Value> {
|
||||
"name".to_string(),
|
||||
json!(sanitize_function_name(&tool_call.name)),
|
||||
);
|
||||
|
||||
if let Some(args) = &tool_call.arguments {
|
||||
if !args.is_empty() {
|
||||
function_call_part
|
||||
.insert("args".to_string(), args.clone().into());
|
||||
}
|
||||
if tool_call.arguments.is_object()
|
||||
&& !tool_call.arguments.as_object().unwrap().is_empty()
|
||||
{
|
||||
function_call_part
|
||||
.insert("args".to_string(), tool_call.arguments.clone());
|
||||
}
|
||||
|
||||
parts.push(json!({
|
||||
"functionCall": function_call_part
|
||||
}));
|
||||
@@ -272,10 +269,7 @@ pub fn response_to_message(response: Value) -> Result<Message> {
|
||||
if let Some(params) = parameters {
|
||||
content.push(MessageContent::tool_request(
|
||||
id,
|
||||
Ok(CallToolRequestParam {
|
||||
name: name.into(),
|
||||
arguments: Some(object(params.clone())),
|
||||
}),
|
||||
Ok(ToolCall::new(&name, params.clone())),
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -347,7 +341,6 @@ pub fn create_request(
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::conversation::message::Message;
|
||||
use rmcp::model::CallToolRequestParam;
|
||||
use rmcp::{model::Content, object};
|
||||
use serde_json::json;
|
||||
|
||||
@@ -355,7 +348,7 @@ mod tests {
|
||||
Message::new(role, 0, vec![MessageContent::text(text.to_string())])
|
||||
}
|
||||
|
||||
fn set_up_tool_request_message(id: &str, tool_call: CallToolRequestParam) -> Message {
|
||||
fn set_up_tool_request_message(id: &str, tool_call: ToolCall) -> Message {
|
||||
Message::new(
|
||||
Role::User,
|
||||
0,
|
||||
@@ -363,14 +356,14 @@ mod tests {
|
||||
)
|
||||
}
|
||||
|
||||
fn set_up_tool_confirmation_message(id: &str, tool_call: CallToolRequestParam) -> Message {
|
||||
fn set_up_tool_confirmation_message(id: &str, tool_call: ToolCall) -> Message {
|
||||
Message::new(
|
||||
Role::User,
|
||||
0,
|
||||
vec![MessageContent::tool_confirmation_request(
|
||||
id.to_string(),
|
||||
tool_call.name.to_string().clone(),
|
||||
tool_call.arguments.unwrap_or_default().clone(),
|
||||
tool_call.name.clone(),
|
||||
tool_call.arguments.clone(),
|
||||
Some("goose would like to call the above tool. Allow? (y/n):".to_string()),
|
||||
)],
|
||||
)
|
||||
@@ -422,19 +415,10 @@ mod tests {
|
||||
"param1": "value1"
|
||||
});
|
||||
let messages = vec![
|
||||
set_up_tool_request_message(
|
||||
"id",
|
||||
CallToolRequestParam {
|
||||
name: "tool_name".into(),
|
||||
arguments: Some(object(arguments.clone())),
|
||||
},
|
||||
),
|
||||
set_up_tool_request_message("id", ToolCall::new("tool_name", arguments.clone())),
|
||||
set_up_tool_confirmation_message(
|
||||
"id2",
|
||||
CallToolRequestParam {
|
||||
name: "tool_name_2".into(),
|
||||
arguments: Some(object(arguments.clone())),
|
||||
},
|
||||
ToolCall::new("tool_name_2", arguments.clone()),
|
||||
),
|
||||
];
|
||||
let payload = format_messages(&messages);
|
||||
@@ -796,14 +780,7 @@ mod tests {
|
||||
assert_eq!(message.content.len(), 1);
|
||||
if let Ok(tool_call) = &message.content[0].as_tool_request().unwrap().tool_call {
|
||||
assert_eq!(tool_call.name, "valid_name");
|
||||
assert_eq!(
|
||||
tool_call
|
||||
.arguments
|
||||
.as_ref()
|
||||
.and_then(|args| args.get("param"))
|
||||
.and_then(|v| v.as_str()),
|
||||
Some("value")
|
||||
);
|
||||
assert_eq!(tool_call.arguments["param"], "value");
|
||||
} else {
|
||||
panic!("Expected valid tool request");
|
||||
}
|
||||
|
||||
@@ -8,9 +8,9 @@ use crate::providers::utils::{
|
||||
use anyhow::{anyhow, Error};
|
||||
use async_stream::try_stream;
|
||||
use futures::Stream;
|
||||
use mcp_core::ToolCall;
|
||||
use rmcp::model::{
|
||||
object, AnnotateAble, CallToolRequestParam, Content, ErrorCode, ErrorData, RawContent,
|
||||
ResourceContents, Role, Tool,
|
||||
AnnotateAble, Content, ErrorCode, ErrorData, RawContent, ResourceContents, Role, Tool,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::{json, Value};
|
||||
@@ -115,7 +115,7 @@ pub fn format_messages(messages: &[Message], image_format: &ImageFormat) -> Vec<
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": sanitized_name,
|
||||
"arguments": tool_call.arguments,
|
||||
"arguments": tool_call.arguments.to_string(),
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -220,7 +220,7 @@ pub fn format_messages(messages: &[Message], image_format: &ImageFormat) -> Vec<
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": sanitized_name,
|
||||
"arguments": tool_call.arguments,
|
||||
"arguments": tool_call.arguments.to_string(),
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -316,10 +316,7 @@ pub fn response_to_message(response: &Value) -> anyhow::Result<Message> {
|
||||
Ok(params) => {
|
||||
content.push(MessageContent::tool_request(
|
||||
id,
|
||||
Ok(CallToolRequestParam {
|
||||
name: function_name.into(),
|
||||
arguments: Some(object(params)),
|
||||
}),
|
||||
Ok(ToolCall::new(&function_name, params)),
|
||||
));
|
||||
}
|
||||
Err(e) => {
|
||||
@@ -518,7 +515,7 @@ where
|
||||
Ok(params) => {
|
||||
MessageContent::tool_request(
|
||||
id.clone(),
|
||||
Ok(CallToolRequestParam { name: function_name.clone().into(), arguments: Some(object(params)) }),
|
||||
Ok(ToolCall::new(function_name.clone(), params)),
|
||||
)
|
||||
},
|
||||
Err(e) => {
|
||||
@@ -824,10 +821,7 @@ mod tests {
|
||||
Message::user().with_text("How are you?"),
|
||||
Message::assistant().with_tool_request(
|
||||
"tool1",
|
||||
Ok(CallToolRequestParam {
|
||||
name: "example".into(),
|
||||
arguments: Some(object!({"param1": "value1"})),
|
||||
}),
|
||||
Ok(ToolCall::new("example", json!({"param1": "value1"}))),
|
||||
),
|
||||
];
|
||||
|
||||
@@ -861,10 +855,7 @@ mod tests {
|
||||
fn test_format_messages_multiple_content() -> anyhow::Result<()> {
|
||||
let mut messages = vec![Message::assistant().with_tool_request(
|
||||
"tool1",
|
||||
Ok(CallToolRequestParam {
|
||||
name: "example".into(),
|
||||
arguments: Some(object!({"param1": "value1"})),
|
||||
}),
|
||||
Ok(ToolCall::new("example", json!({"param1": "value1"}))),
|
||||
)];
|
||||
|
||||
// Get the ID from the tool request to use in the response
|
||||
@@ -1009,7 +1000,7 @@ mod tests {
|
||||
if let MessageContent::ToolRequest(request) = &message.content[0] {
|
||||
let tool_call = request.tool_call.as_ref().unwrap();
|
||||
assert_eq!(tool_call.name, "example_fn");
|
||||
assert_eq!(tool_call.arguments, Some(object!({"param": "value"})));
|
||||
assert_eq!(tool_call.arguments, json!({"param": "value"}));
|
||||
} else {
|
||||
panic!("Expected ToolRequest content");
|
||||
}
|
||||
@@ -1080,7 +1071,7 @@ mod tests {
|
||||
if let MessageContent::ToolRequest(request) = &message.content[0] {
|
||||
let tool_call = request.tool_call.as_ref().unwrap();
|
||||
assert_eq!(tool_call.name, "example_fn");
|
||||
assert_eq!(tool_call.arguments, Some(object!({})));
|
||||
assert_eq!(tool_call.arguments, json!({}));
|
||||
} else {
|
||||
panic!("Expected ToolRequest content");
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ use crate::model::ModelConfig;
|
||||
use crate::providers::base::Usage;
|
||||
use crate::providers::errors::ProviderError;
|
||||
use anyhow::{anyhow, Result};
|
||||
use rmcp::model::{object, CallToolRequestParam, Role, Tool};
|
||||
use rmcp::object;
|
||||
use mcp_core::tool::ToolCall;
|
||||
use rmcp::model::{Role, Tool};
|
||||
use serde_json::{json, Value};
|
||||
use std::collections::HashSet;
|
||||
|
||||
@@ -181,22 +181,16 @@ pub fn parse_streaming_response(sse_data: &str) -> Result<Message> {
|
||||
}
|
||||
|
||||
// Add tool use if complete
|
||||
if let Some((id, name)) = tool_use_id.zip(tool_name) {
|
||||
if let (Some(id), Some(name)) = (&tool_use_id, &tool_name) {
|
||||
if !tool_input.is_empty() {
|
||||
let input_value = serde_json::from_str::<Value>(&tool_input)
|
||||
.unwrap_or_else(|_| Value::String(tool_input.clone()));
|
||||
let tool_call = CallToolRequestParam {
|
||||
name: name.into(),
|
||||
arguments: Some(object(input_value)),
|
||||
};
|
||||
message = message.with_tool_request(&id, Ok(tool_call));
|
||||
} else {
|
||||
let tool_call = ToolCall::new(name, input_value);
|
||||
message = message.with_tool_request(id, Ok(tool_call));
|
||||
} else if tool_name.is_some() {
|
||||
// Tool with no input - use empty object
|
||||
let tool_call = CallToolRequestParam {
|
||||
name: name.into(),
|
||||
arguments: Some(object!({})),
|
||||
};
|
||||
message = message.with_tool_request(&id, Ok(tool_call));
|
||||
let tool_call = ToolCall::new(name, Value::Object(serde_json::Map::new()));
|
||||
message = message.with_tool_request(id, Ok(tool_call));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,18 +238,14 @@ pub fn response_to_message(response: &Value) -> Result<Message> {
|
||||
let name = content
|
||||
.get("name")
|
||||
.and_then(|n| n.as_str())
|
||||
.ok_or_else(|| anyhow!("Missing tool_use name"))?
|
||||
.to_string();
|
||||
.ok_or_else(|| anyhow!("Missing tool_use name"))?;
|
||||
|
||||
let input = content
|
||||
.get("input")
|
||||
.ok_or_else(|| anyhow!("Missing tool input"))?
|
||||
.clone();
|
||||
|
||||
let tool_call = CallToolRequestParam {
|
||||
name: name.into(),
|
||||
arguments: Some(object(input)),
|
||||
};
|
||||
let tool_call = ToolCall::new(name, input);
|
||||
message = message.with_tool_request(id, Ok(tool_call));
|
||||
}
|
||||
Some("thinking") => {
|
||||
@@ -435,7 +425,7 @@ mod tests {
|
||||
if let MessageContent::ToolRequest(tool_request) = &message.content[0] {
|
||||
let tool_call = tool_request.tool_call.as_ref().unwrap();
|
||||
assert_eq!(tool_call.name, "calculator");
|
||||
assert_eq!(tool_call.arguments, Some(object!({"expression": "2 + 2"})));
|
||||
assert_eq!(tool_call.arguments, json!({"expression": "2 + 2"}));
|
||||
} else {
|
||||
panic!("Expected ToolRequest content");
|
||||
}
|
||||
@@ -546,7 +536,7 @@ data: {"id":"a9537c2c-2017-4906-9817-2456168d89fa","model":"claude-sonnet-4-2025
|
||||
if let MessageContent::ToolRequest(tool_request) = &message.content[1] {
|
||||
let tool_call = tool_request.tool_call.as_ref().unwrap();
|
||||
assert_eq!(tool_call.name, "get_stock_price");
|
||||
assert_eq!(tool_call.arguments, Some(object!({"symbol": "NVDA"})));
|
||||
assert_eq!(tool_call.arguments, json!({"symbol": "NVDA"}));
|
||||
assert_eq!(tool_request.id, "tooluse_FB_nOElDTAOKa-YnVWI5Uw");
|
||||
} else {
|
||||
panic!("Expected ToolRequest content second");
|
||||
@@ -689,12 +679,10 @@ data: {"id":"a9537c2c-2017-4906-9817-2456168d89fa","model":"claude-sonnet-4-2025
|
||||
#[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
|
||||
let tool_call = CallToolRequestParam {
|
||||
name: "calculator".into(),
|
||||
arguments: Some(object!({"expression": "2 + 2"})),
|
||||
};
|
||||
let tool_call = ToolCall::new("calculator", json!({"expression": "2 + 2"}));
|
||||
|
||||
let messages = vec![
|
||||
Message::user().with_text("Calculate 2 + 2"),
|
||||
|
||||
@@ -38,8 +38,9 @@ use crate::conversation::Conversation;
|
||||
use crate::model::ModelConfig;
|
||||
use crate::providers::formats::openai::create_request;
|
||||
use anyhow::Result;
|
||||
use mcp_core::tool::ToolCall;
|
||||
use reqwest::Client;
|
||||
use rmcp::model::{object, CallToolRequestParam, RawContent, Tool};
|
||||
use rmcp::model::{RawContent, Tool};
|
||||
use serde_json::{json, Value};
|
||||
use std::ops::Deref;
|
||||
use std::time::Duration;
|
||||
@@ -59,7 +60,7 @@ pub trait ToolInterpreter {
|
||||
&self,
|
||||
content: &str,
|
||||
tools: &[Tool],
|
||||
) -> Result<Vec<CallToolRequestParam>, ProviderError>;
|
||||
) -> Result<Vec<ToolCall>, ProviderError>;
|
||||
}
|
||||
|
||||
/// Ollama-specific implementation of the ToolInterpreter trait
|
||||
@@ -197,9 +198,7 @@ impl OllamaInterpreter {
|
||||
Ok(response_json)
|
||||
}
|
||||
|
||||
fn process_interpreter_response(
|
||||
response: &Value,
|
||||
) -> Result<Vec<CallToolRequestParam>, ProviderError> {
|
||||
fn process_interpreter_response(response: &Value) -> Result<Vec<ToolCall>, ProviderError> {
|
||||
let mut tool_calls = Vec::new();
|
||||
tracing::info!(
|
||||
"Tool interpreter response is {}",
|
||||
@@ -220,14 +219,12 @@ impl OllamaInterpreter {
|
||||
&& item.get("name").is_some()
|
||||
&& item.get("arguments").is_some()
|
||||
{
|
||||
// Create ToolCall directly from the JSON data
|
||||
let name = item["name"].as_str().unwrap_or_default().to_string();
|
||||
let arguments = item["arguments"].clone();
|
||||
|
||||
// Add the tool call to our result vector
|
||||
tool_calls.push(CallToolRequestParam {
|
||||
name: name.into(),
|
||||
arguments: Some(object(arguments)),
|
||||
});
|
||||
tool_calls.push(ToolCall::new(name, arguments));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -245,7 +242,7 @@ impl ToolInterpreter for OllamaInterpreter {
|
||||
&self,
|
||||
last_assistant_msg: &str,
|
||||
tools: &[Tool],
|
||||
) -> Result<Vec<CallToolRequestParam>, ProviderError> {
|
||||
) -> Result<Vec<ToolCall>, ProviderError> {
|
||||
if tools.is_empty() {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@ 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::mcp_utils::ToolResult;
|
||||
use crate::model::ModelConfig;
|
||||
use rmcp::model::{object, CallToolRequestParam, Role, Tool};
|
||||
use mcp_core::{ToolCall, ToolResult};
|
||||
use rmcp::model::{Role, Tool};
|
||||
|
||||
// ---------- Capability Flags ----------
|
||||
#[derive(Debug)]
|
||||
@@ -339,19 +339,12 @@ impl Provider for VeniceProvider {
|
||||
.iter()
|
||||
.filter_map(|tr| {
|
||||
if let ToolResult::Ok(tool_call) = &tr.tool_call {
|
||||
// Safely convert arguments to a JSON string
|
||||
let args_str = tool_call
|
||||
.arguments
|
||||
.as_ref() // borrow the Option contents
|
||||
.map(|map| serde_json::to_string(map).unwrap_or_default())
|
||||
.unwrap_or_default();
|
||||
|
||||
// Log tool call details for debugging
|
||||
tracing::debug!(
|
||||
"Tool call conversion: id={}, name={}, args_len={}",
|
||||
tr.id,
|
||||
tool_call.name,
|
||||
args_str.len()
|
||||
tool_call.arguments.to_string().len()
|
||||
);
|
||||
|
||||
// Convert to Venice format
|
||||
@@ -360,7 +353,7 @@ impl Provider for VeniceProvider {
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": tool_call.name,
|
||||
"arguments": args_str
|
||||
"arguments": tool_call.arguments.to_string()
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
@@ -460,10 +453,8 @@ impl Provider for VeniceProvider {
|
||||
function["arguments"].clone()
|
||||
};
|
||||
|
||||
let tool_call = CallToolRequestParam {
|
||||
name: name.into(),
|
||||
arguments: Some(object(arguments)),
|
||||
};
|
||||
// Create a ToolCall using the function name and arguments
|
||||
let tool_call = ToolCall { name, arguments };
|
||||
|
||||
// Create a ToolRequest MessageContent
|
||||
let tool_request = MessageContent::tool_request(id, ToolResult::Ok(tool_call));
|
||||
|
||||
Reference in New Issue
Block a user