Implement SEP-1577: Sampling With Tools (#628)
* feat: implement SEP-1577 sampling with tools support * feat: add TryFrom<Content> for backward-compatible migration
This commit is contained in:
parent
be23334f9d
commit
8bd3fcb890
1 changed files with 1850 additions and 141 deletions
|
|
@ -13,14 +13,8 @@ use tokio_util::sync::CancellationToken;
|
|||
#[tokio::test]
|
||||
async fn test_message_roles() {
|
||||
let messages = vec![
|
||||
SamplingMessage {
|
||||
role: Role::User,
|
||||
content: Content::text("user message"),
|
||||
},
|
||||
SamplingMessage {
|
||||
role: Role::Assistant,
|
||||
content: Content::text("assistant message"),
|
||||
},
|
||||
SamplingMessage::user_text("user message"),
|
||||
SamplingMessage::assistant_text("assistant message"),
|
||||
];
|
||||
|
||||
// Verify all roles can be serialized/deserialized correctly
|
||||
|
|
@ -50,10 +44,7 @@ async fn test_context_inclusion_integration() -> anyhow::Result<()> {
|
|||
params: CreateMessageRequestParams {
|
||||
meta: None,
|
||||
task: None,
|
||||
messages: vec![SamplingMessage {
|
||||
role: Role::User,
|
||||
content: Content::text("test message"),
|
||||
}],
|
||||
messages: vec![SamplingMessage::user_text("test message")],
|
||||
include_context: Some(ContextInclusion::ThisServer),
|
||||
model_preferences: None,
|
||||
system_prompt: None,
|
||||
|
|
@ -61,6 +52,8 @@ async fn test_context_inclusion_integration() -> anyhow::Result<()> {
|
|||
max_tokens: 100,
|
||||
stop_sequences: None,
|
||||
metadata: None,
|
||||
tools: None,
|
||||
tool_choice: None,
|
||||
},
|
||||
extensions: Default::default(),
|
||||
});
|
||||
|
|
@ -79,7 +72,15 @@ async fn test_context_inclusion_integration() -> anyhow::Result<()> {
|
|||
.await?;
|
||||
|
||||
if let ClientResult::CreateMessageResult(result) = result {
|
||||
let text = result.message.content.as_text().unwrap().text.as_str();
|
||||
let text = result
|
||||
.message
|
||||
.content
|
||||
.first()
|
||||
.unwrap()
|
||||
.as_text()
|
||||
.unwrap()
|
||||
.text
|
||||
.as_str();
|
||||
assert!(
|
||||
text.contains("test context"),
|
||||
"Response should include context for ThisServer"
|
||||
|
|
@ -94,10 +95,7 @@ async fn test_context_inclusion_integration() -> anyhow::Result<()> {
|
|||
params: CreateMessageRequestParams {
|
||||
meta: None,
|
||||
task: None,
|
||||
messages: vec![SamplingMessage {
|
||||
role: Role::User,
|
||||
content: Content::text("test message"),
|
||||
}],
|
||||
messages: vec![SamplingMessage::user_text("test message")],
|
||||
include_context: Some(ContextInclusion::AllServers),
|
||||
model_preferences: None,
|
||||
system_prompt: None,
|
||||
|
|
@ -105,6 +103,8 @@ async fn test_context_inclusion_integration() -> anyhow::Result<()> {
|
|||
max_tokens: 100,
|
||||
stop_sequences: None,
|
||||
metadata: None,
|
||||
tools: None,
|
||||
tool_choice: None,
|
||||
},
|
||||
extensions: Default::default(),
|
||||
});
|
||||
|
|
@ -123,7 +123,15 @@ async fn test_context_inclusion_integration() -> anyhow::Result<()> {
|
|||
.await?;
|
||||
|
||||
if let ClientResult::CreateMessageResult(result) = result {
|
||||
let text = result.message.content.as_text().unwrap().text.as_str();
|
||||
let text = result
|
||||
.message
|
||||
.content
|
||||
.first()
|
||||
.unwrap()
|
||||
.as_text()
|
||||
.unwrap()
|
||||
.text
|
||||
.as_str();
|
||||
assert!(
|
||||
text.contains("test context"),
|
||||
"Response should include context for AllServers"
|
||||
|
|
@ -138,10 +146,7 @@ async fn test_context_inclusion_integration() -> anyhow::Result<()> {
|
|||
params: CreateMessageRequestParams {
|
||||
meta: None,
|
||||
task: None,
|
||||
messages: vec![SamplingMessage {
|
||||
role: Role::User,
|
||||
content: Content::text("test message"),
|
||||
}],
|
||||
messages: vec![SamplingMessage::user_text("test message")],
|
||||
include_context: Some(ContextInclusion::None),
|
||||
model_preferences: None,
|
||||
system_prompt: None,
|
||||
|
|
@ -149,6 +154,8 @@ async fn test_context_inclusion_integration() -> anyhow::Result<()> {
|
|||
max_tokens: 100,
|
||||
stop_sequences: None,
|
||||
metadata: None,
|
||||
tools: None,
|
||||
tool_choice: None,
|
||||
},
|
||||
extensions: Default::default(),
|
||||
});
|
||||
|
|
@ -167,7 +174,15 @@ async fn test_context_inclusion_integration() -> anyhow::Result<()> {
|
|||
.await?;
|
||||
|
||||
if let ClientResult::CreateMessageResult(result) = result {
|
||||
let text = result.message.content.as_text().unwrap().text.as_str();
|
||||
let text = result
|
||||
.message
|
||||
.content
|
||||
.first()
|
||||
.unwrap()
|
||||
.as_text()
|
||||
.unwrap()
|
||||
.text
|
||||
.as_str();
|
||||
assert!(
|
||||
!text.contains("test context"),
|
||||
"Response should not include context for None"
|
||||
|
|
@ -202,10 +217,7 @@ async fn test_context_inclusion_ignored_integration() -> anyhow::Result<()> {
|
|||
params: CreateMessageRequestParams {
|
||||
meta: None,
|
||||
task: None,
|
||||
messages: vec![SamplingMessage {
|
||||
role: Role::User,
|
||||
content: Content::text("test message"),
|
||||
}],
|
||||
messages: vec![SamplingMessage::user_text("test message")],
|
||||
include_context: Some(ContextInclusion::ThisServer),
|
||||
model_preferences: None,
|
||||
system_prompt: None,
|
||||
|
|
@ -213,6 +225,8 @@ async fn test_context_inclusion_ignored_integration() -> anyhow::Result<()> {
|
|||
max_tokens: 100,
|
||||
stop_sequences: None,
|
||||
metadata: None,
|
||||
tools: None,
|
||||
tool_choice: None,
|
||||
},
|
||||
extensions: Default::default(),
|
||||
});
|
||||
|
|
@ -231,7 +245,15 @@ async fn test_context_inclusion_ignored_integration() -> anyhow::Result<()> {
|
|||
.await?;
|
||||
|
||||
if let ClientResult::CreateMessageResult(result) = result {
|
||||
let text = result.message.content.as_text().unwrap().text.as_str();
|
||||
let text = result
|
||||
.message
|
||||
.content
|
||||
.first()
|
||||
.unwrap()
|
||||
.as_text()
|
||||
.unwrap()
|
||||
.text
|
||||
.as_str();
|
||||
assert!(
|
||||
!text.contains("test context"),
|
||||
"Context should be ignored when client chooses not to honor requests"
|
||||
|
|
@ -266,14 +288,8 @@ async fn test_message_sequence_integration() -> anyhow::Result<()> {
|
|||
meta: None,
|
||||
task: None,
|
||||
messages: vec![
|
||||
SamplingMessage {
|
||||
role: Role::User,
|
||||
content: Content::text("first message"),
|
||||
},
|
||||
SamplingMessage {
|
||||
role: Role::Assistant,
|
||||
content: Content::text("second message"),
|
||||
},
|
||||
SamplingMessage::user_text("first message"),
|
||||
SamplingMessage::assistant_text("second message"),
|
||||
],
|
||||
include_context: Some(ContextInclusion::ThisServer),
|
||||
model_preferences: None,
|
||||
|
|
@ -282,6 +298,8 @@ async fn test_message_sequence_integration() -> anyhow::Result<()> {
|
|||
max_tokens: 100,
|
||||
stop_sequences: None,
|
||||
metadata: None,
|
||||
tools: None,
|
||||
tool_choice: None,
|
||||
},
|
||||
extensions: Default::default(),
|
||||
});
|
||||
|
|
@ -300,7 +318,15 @@ async fn test_message_sequence_integration() -> anyhow::Result<()> {
|
|||
.await?;
|
||||
|
||||
if let ClientResult::CreateMessageResult(result) = result {
|
||||
let text = result.message.content.as_text().unwrap().text.as_str();
|
||||
let text = result
|
||||
.message
|
||||
.content
|
||||
.first()
|
||||
.unwrap()
|
||||
.as_text()
|
||||
.unwrap()
|
||||
.text
|
||||
.as_str();
|
||||
assert!(
|
||||
text.contains("test context"),
|
||||
"Response should include context when ThisServer is specified"
|
||||
|
|
@ -339,18 +365,9 @@ async fn test_message_sequence_validation_integration() -> anyhow::Result<()> {
|
|||
meta: None,
|
||||
task: None,
|
||||
messages: vec![
|
||||
SamplingMessage {
|
||||
role: Role::User,
|
||||
content: Content::text("first user message"),
|
||||
},
|
||||
SamplingMessage {
|
||||
role: Role::Assistant,
|
||||
content: Content::text("first assistant response"),
|
||||
},
|
||||
SamplingMessage {
|
||||
role: Role::User,
|
||||
content: Content::text("second user message"),
|
||||
},
|
||||
SamplingMessage::user_text("first user message"),
|
||||
SamplingMessage::assistant_text("first assistant response"),
|
||||
SamplingMessage::user_text("second user message"),
|
||||
],
|
||||
include_context: None,
|
||||
model_preferences: None,
|
||||
|
|
@ -359,6 +376,8 @@ async fn test_message_sequence_validation_integration() -> anyhow::Result<()> {
|
|||
max_tokens: 100,
|
||||
stop_sequences: None,
|
||||
metadata: None,
|
||||
tools: None,
|
||||
tool_choice: None,
|
||||
},
|
||||
extensions: Default::default(),
|
||||
});
|
||||
|
|
@ -384,10 +403,7 @@ async fn test_message_sequence_validation_integration() -> anyhow::Result<()> {
|
|||
params: CreateMessageRequestParams {
|
||||
meta: None,
|
||||
task: None,
|
||||
messages: vec![SamplingMessage {
|
||||
role: Role::Assistant,
|
||||
content: Content::text("assistant message"),
|
||||
}],
|
||||
messages: vec![SamplingMessage::assistant_text("assistant message")],
|
||||
include_context: None,
|
||||
model_preferences: None,
|
||||
system_prompt: None,
|
||||
|
|
@ -395,6 +411,8 @@ async fn test_message_sequence_validation_integration() -> anyhow::Result<()> {
|
|||
max_tokens: 100,
|
||||
stop_sequences: None,
|
||||
metadata: None,
|
||||
tools: None,
|
||||
tool_choice: None,
|
||||
},
|
||||
extensions: Default::default(),
|
||||
});
|
||||
|
|
@ -439,10 +457,7 @@ async fn test_selective_context_handling_integration() -> anyhow::Result<()> {
|
|||
params: CreateMessageRequestParams {
|
||||
meta: None,
|
||||
task: None,
|
||||
messages: vec![SamplingMessage {
|
||||
role: Role::User,
|
||||
content: Content::text("test message"),
|
||||
}],
|
||||
messages: vec![SamplingMessage::user_text("test message")],
|
||||
include_context: Some(ContextInclusion::ThisServer),
|
||||
model_preferences: None,
|
||||
system_prompt: None,
|
||||
|
|
@ -450,6 +465,8 @@ async fn test_selective_context_handling_integration() -> anyhow::Result<()> {
|
|||
max_tokens: 100,
|
||||
stop_sequences: None,
|
||||
metadata: None,
|
||||
tools: None,
|
||||
tool_choice: None,
|
||||
},
|
||||
extensions: Default::default(),
|
||||
});
|
||||
|
|
@ -468,7 +485,15 @@ async fn test_selective_context_handling_integration() -> anyhow::Result<()> {
|
|||
.await?;
|
||||
|
||||
if let ClientResult::CreateMessageResult(result) = result {
|
||||
let text = result.message.content.as_text().unwrap().text.as_str();
|
||||
let text = result
|
||||
.message
|
||||
.content
|
||||
.first()
|
||||
.unwrap()
|
||||
.as_text()
|
||||
.unwrap()
|
||||
.text
|
||||
.as_str();
|
||||
assert!(
|
||||
text.contains("test context"),
|
||||
"ThisServer context request should be honored"
|
||||
|
|
@ -481,10 +506,7 @@ async fn test_selective_context_handling_integration() -> anyhow::Result<()> {
|
|||
params: CreateMessageRequestParams {
|
||||
meta: None,
|
||||
task: None,
|
||||
messages: vec![SamplingMessage {
|
||||
role: Role::User,
|
||||
content: Content::text("test message"),
|
||||
}],
|
||||
messages: vec![SamplingMessage::user_text("test message")],
|
||||
include_context: Some(ContextInclusion::AllServers),
|
||||
model_preferences: None,
|
||||
system_prompt: None,
|
||||
|
|
@ -492,6 +514,8 @@ async fn test_selective_context_handling_integration() -> anyhow::Result<()> {
|
|||
max_tokens: 100,
|
||||
stop_sequences: None,
|
||||
metadata: None,
|
||||
tools: None,
|
||||
tool_choice: None,
|
||||
},
|
||||
extensions: Default::default(),
|
||||
});
|
||||
|
|
@ -510,7 +534,15 @@ async fn test_selective_context_handling_integration() -> anyhow::Result<()> {
|
|||
.await?;
|
||||
|
||||
if let ClientResult::CreateMessageResult(result) = result {
|
||||
let text = result.message.content.as_text().unwrap().text.as_str();
|
||||
let text = result
|
||||
.message
|
||||
.content
|
||||
.first()
|
||||
.unwrap()
|
||||
.as_text()
|
||||
.unwrap()
|
||||
.text
|
||||
.as_str();
|
||||
assert!(
|
||||
!text.contains("test context"),
|
||||
"AllServers context request should be ignored"
|
||||
|
|
@ -540,10 +572,7 @@ async fn test_context_inclusion() -> anyhow::Result<()> {
|
|||
params: CreateMessageRequestParams {
|
||||
meta: None,
|
||||
task: None,
|
||||
messages: vec![SamplingMessage {
|
||||
role: Role::User,
|
||||
content: Content::text("test"),
|
||||
}],
|
||||
messages: vec![SamplingMessage::user_text("test")],
|
||||
include_context: Some(ContextInclusion::ThisServer),
|
||||
model_preferences: None,
|
||||
system_prompt: None,
|
||||
|
|
@ -551,6 +580,8 @@ async fn test_context_inclusion() -> anyhow::Result<()> {
|
|||
max_tokens: 100,
|
||||
stop_sequences: None,
|
||||
metadata: None,
|
||||
tools: None,
|
||||
tool_choice: None,
|
||||
},
|
||||
extensions: Default::default(),
|
||||
});
|
||||
|
|
@ -569,7 +600,15 @@ async fn test_context_inclusion() -> anyhow::Result<()> {
|
|||
.await?;
|
||||
|
||||
if let ClientResult::CreateMessageResult(result) = result {
|
||||
let text = result.message.content.as_text().unwrap().text.as_str();
|
||||
let text = result
|
||||
.message
|
||||
.content
|
||||
.first()
|
||||
.unwrap()
|
||||
.as_text()
|
||||
.unwrap()
|
||||
.text
|
||||
.as_str();
|
||||
assert!(text.contains("test context"));
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue