anthropic: Fix error when attaching multiple images (#32092)
Closes #31438 Release Notes: - agent: Fixed an edge case were the request would fail when using Claude and multiple images were attached --------- Co-authored-by: Richard Feldman <oss@rtfeldman.com>
This commit is contained in:
parent
d2c265c71f
commit
28da99cc06
1 changed files with 101 additions and 13 deletions
|
@ -523,14 +523,7 @@ pub fn into_anthropic(
|
||||||
|
|
||||||
match message.role {
|
match message.role {
|
||||||
Role::User | Role::Assistant => {
|
Role::User | Role::Assistant => {
|
||||||
let cache_control = if message.cache {
|
let mut anthropic_message_content: Vec<anthropic::RequestContent> = message
|
||||||
Some(anthropic::CacheControl {
|
|
||||||
cache_type: anthropic::CacheControlType::Ephemeral,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let anthropic_message_content: Vec<anthropic::RequestContent> = message
|
|
||||||
.content
|
.content
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|content| match content {
|
.filter_map(|content| match content {
|
||||||
|
@ -538,7 +531,7 @@ pub fn into_anthropic(
|
||||||
if !text.is_empty() {
|
if !text.is_empty() {
|
||||||
Some(anthropic::RequestContent::Text {
|
Some(anthropic::RequestContent::Text {
|
||||||
text,
|
text,
|
||||||
cache_control,
|
cache_control: None,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -552,7 +545,7 @@ pub fn into_anthropic(
|
||||||
Some(anthropic::RequestContent::Thinking {
|
Some(anthropic::RequestContent::Thinking {
|
||||||
thinking,
|
thinking,
|
||||||
signature: signature.unwrap_or_default(),
|
signature: signature.unwrap_or_default(),
|
||||||
cache_control,
|
cache_control: None,
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
@ -573,14 +566,14 @@ pub fn into_anthropic(
|
||||||
media_type: "image/png".to_string(),
|
media_type: "image/png".to_string(),
|
||||||
data: image.source.to_string(),
|
data: image.source.to_string(),
|
||||||
},
|
},
|
||||||
cache_control,
|
cache_control: None,
|
||||||
}),
|
}),
|
||||||
MessageContent::ToolUse(tool_use) => {
|
MessageContent::ToolUse(tool_use) => {
|
||||||
Some(anthropic::RequestContent::ToolUse {
|
Some(anthropic::RequestContent::ToolUse {
|
||||||
id: tool_use.id.to_string(),
|
id: tool_use.id.to_string(),
|
||||||
name: tool_use.name.to_string(),
|
name: tool_use.name.to_string(),
|
||||||
input: tool_use.input,
|
input: tool_use.input,
|
||||||
cache_control,
|
cache_control: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
MessageContent::ToolResult(tool_result) => {
|
MessageContent::ToolResult(tool_result) => {
|
||||||
|
@ -601,7 +594,7 @@ pub fn into_anthropic(
|
||||||
}])
|
}])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
cache_control,
|
cache_control: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -617,6 +610,29 @@ pub fn into_anthropic(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Mark the last segment of the message as cached
|
||||||
|
if message.cache {
|
||||||
|
let cache_control_value = Some(anthropic::CacheControl {
|
||||||
|
cache_type: anthropic::CacheControlType::Ephemeral,
|
||||||
|
});
|
||||||
|
for message_content in anthropic_message_content.iter_mut().rev() {
|
||||||
|
match message_content {
|
||||||
|
anthropic::RequestContent::RedactedThinking { .. } => {
|
||||||
|
// Caching is not possible, fallback to next message
|
||||||
|
}
|
||||||
|
anthropic::RequestContent::Text { cache_control, .. }
|
||||||
|
| anthropic::RequestContent::Thinking { cache_control, .. }
|
||||||
|
| anthropic::RequestContent::Image { cache_control, .. }
|
||||||
|
| anthropic::RequestContent::ToolUse { cache_control, .. }
|
||||||
|
| anthropic::RequestContent::ToolResult { cache_control, .. } => {
|
||||||
|
*cache_control = cache_control_value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
new_messages.push(anthropic::Message {
|
new_messages.push(anthropic::Message {
|
||||||
role: anthropic_role,
|
role: anthropic_role,
|
||||||
content: anthropic_message_content,
|
content: anthropic_message_content,
|
||||||
|
@ -1068,3 +1084,75 @@ impl Render for ConfigurationView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use anthropic::AnthropicModelMode;
|
||||||
|
use language_model::{LanguageModelRequestMessage, MessageContent};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cache_control_only_on_last_segment() {
|
||||||
|
let request = LanguageModelRequest {
|
||||||
|
messages: vec![LanguageModelRequestMessage {
|
||||||
|
role: Role::User,
|
||||||
|
content: vec![
|
||||||
|
MessageContent::Text("Some prompt".to_string()),
|
||||||
|
MessageContent::Image(language_model::LanguageModelImage::empty()),
|
||||||
|
MessageContent::Image(language_model::LanguageModelImage::empty()),
|
||||||
|
MessageContent::Image(language_model::LanguageModelImage::empty()),
|
||||||
|
MessageContent::Image(language_model::LanguageModelImage::empty()),
|
||||||
|
],
|
||||||
|
cache: true,
|
||||||
|
}],
|
||||||
|
thread_id: None,
|
||||||
|
prompt_id: None,
|
||||||
|
intent: None,
|
||||||
|
mode: None,
|
||||||
|
stop: vec![],
|
||||||
|
temperature: None,
|
||||||
|
tools: vec![],
|
||||||
|
tool_choice: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
let anthropic_request = into_anthropic(
|
||||||
|
request,
|
||||||
|
"claude-3-5-sonnet".to_string(),
|
||||||
|
0.7,
|
||||||
|
4096,
|
||||||
|
AnthropicModelMode::Default,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(anthropic_request.messages.len(), 1);
|
||||||
|
|
||||||
|
let message = &anthropic_request.messages[0];
|
||||||
|
assert_eq!(message.content.len(), 5);
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
message.content[0],
|
||||||
|
anthropic::RequestContent::Text {
|
||||||
|
cache_control: None,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
));
|
||||||
|
for i in 1..3 {
|
||||||
|
assert!(matches!(
|
||||||
|
message.content[i],
|
||||||
|
anthropic::RequestContent::Image {
|
||||||
|
cache_control: None,
|
||||||
|
..
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
assert!(matches!(
|
||||||
|
message.content[4],
|
||||||
|
anthropic::RequestContent::Image {
|
||||||
|
cache_control: Some(anthropic::CacheControl {
|
||||||
|
cache_type: anthropic::CacheControlType::Ephemeral,
|
||||||
|
}),
|
||||||
|
..
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue