Skip to content

Commit

Permalink
feat: enable prompt cache for anthropic (#631)
Browse files Browse the repository at this point in the history
  • Loading branch information
yingjiehe-xyz authored Jan 16, 2025
1 parent 3727574 commit 3454855
Showing 1 changed file with 49 additions and 3 deletions.
52 changes: 49 additions & 3 deletions crates/goose/src/providers/anthropic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,26 @@ impl AnthropicProvider {
}
}

// Add "cache_control" to the last tool spec, if any. This means that all tool definitions,
// will be cached as a single prefix.
if let Some(last_tool) = tool_specs.last_mut() {
last_tool
.as_object_mut()
.unwrap()
.insert("cache_control".to_string(), json!({ "type": "ephemeral" }));
}

tool_specs
}

fn system_to_anthropic_spec(system: &str) -> Value {
json!([{
"type": "text",
"text": system,
"cache_control": { "type": "ephemeral" }
}])
}

fn messages_to_anthropic_spec(messages: &[Message]) -> Vec<Value> {
let mut anthropic_messages = Vec::new();

Expand Down Expand Up @@ -136,6 +153,30 @@ impl AnthropicProvider {
}));
}

// Add "cache_control" to the last and second-to-last "user" messages.
// During each turn, we mark the final message with cache_control so the conversation can be
// incrementally cached. The second-to-last user message is also marked for caching with the
// cache_control parameter, so that this checkpoint can read from the previous cache.
let mut user_count = 0;
for message in anthropic_messages.iter_mut().rev() {
if message.get("role") == Some(&json!("user")) {
if let Some(content) = message.get_mut("content") {
if let Some(content_array) = content.as_array_mut() {
if let Some(last_content) = content_array.last_mut() {
last_content.as_object_mut().unwrap().insert(
"cache_control".to_string(),
json!({ "type": "ephemeral" }),
);
}
}
}
user_count += 1;
if user_count >= 2 {
break;
}
}
}

anthropic_messages
}

Expand Down Expand Up @@ -225,6 +266,7 @@ impl Provider for AnthropicProvider {
) -> Result<(Message, ProviderUsage)> {
let anthropic_messages = Self::messages_to_anthropic_spec(messages);
let tool_specs = Self::tools_to_anthropic_spec(tools);
let system_spec = Self::system_to_anthropic_spec(system);

// Check if we have any messages to send
if anthropic_messages.is_empty() {
Expand All @@ -242,7 +284,7 @@ impl Provider for AnthropicProvider {
payload
.as_object_mut()
.unwrap()
.insert("system".to_string(), json!(system));
.insert("system".to_string(), json!(system_spec));
}

// Add tools if present
Expand Down Expand Up @@ -348,7 +390,9 @@ mod tests {
"stop_sequence": null,
"usage": {
"input_tokens": 12,
"output_tokens": 15
"output_tokens": 15,
"cache_creation_input_tokens": 12,
"cache_read_input_tokens": 0
}
});

Expand Down Expand Up @@ -394,7 +438,9 @@ mod tests {
"stop_sequence": null,
"usage": {
"input_tokens": 15,
"output_tokens": 20
"output_tokens": 20,
"cache_creation_input_tokens": 15,
"cache_read_input_tokens": 0,
}
});

Expand Down

0 comments on commit 3454855

Please sign in to comment.