Skip to content

Commit

Permalink
Add support for prompt caching
Browse files Browse the repository at this point in the history
  • Loading branch information
jgaskins committed Aug 15, 2024
1 parent 0d13729 commit 841613b
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 14 deletions.
1 change: 1 addition & 0 deletions src/anthropic.cr
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ require "./version"
require "./messages"
require "./message"
require "./model"
require "./cache_control"
14 changes: 14 additions & 0 deletions src/cache_control.cr
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
require "./resource"

struct Anthropic::CacheControl
include Resource

getter type : Type

def initialize(@type = :ephemeral)
end

enum Type
Ephemeral
end
end
2 changes: 2 additions & 0 deletions src/generated_message.cr
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ struct Anthropic::GeneratedMessage

getter input_tokens : Int64
getter output_tokens : Int64
getter cache_creation_input_tokens : Int64 = 0
getter cache_read_input_tokens : Int64 = 0
end

enum StopReason
Expand Down
13 changes: 9 additions & 4 deletions src/message_content.cr
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
require "./resource"
require "json"
require "base64"

require "./resource"
require "./cache_control"

module Anthropic
abstract struct MessageContent
include Resource

abstract def type : String

getter cache_control : CacheControl?

use_json_discriminator "type", {
text: Text,
image: Image,
Expand All @@ -26,7 +30,7 @@ module Anthropic
getter type : String = "text"
getter text : String

def initialize(@text)
def initialize(@text, *, @cache_control = nil)
end

def to_s(io) : Nil
Expand All @@ -40,15 +44,16 @@ module Anthropic
getter type : String = "image"
getter source : Source

def self.base64(media_type : Source::MediaType, data : String)
def self.base64(media_type : Source::MediaType, data : String, cache_control : CacheControl? = nil)
new(
type: :base64,
media_type: media_type,
data: Base64.strict_encode(data),
cache_control: cache_control,
)
end

def initialize(*, type : Source::Type, media_type : Source::MediaType, data : String)
def initialize(*, type : Source::Type, media_type : Source::MediaType, data : String, @cache_control = nil)
@source = Source.new(type: type, media_type: media_type, data: data)
end

Expand Down
27 changes: 17 additions & 10 deletions src/messages.cr
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ require "./event_source"

module Anthropic
struct Messages < API
CREATE_HEADERS = HTTP::Headers{
"anthropic-beta" => {
# Not sure if this one is still necessary because tools seem to work
# without it, but keeping it here until I see something official.
"tools-2024-04-04",

# 3.5 Sonnet only supports 4k tokens by default, but you can opt into
# up to 8k output tokens.
# https://x.com/alexalbert__/status/1812921642143900036
"max-tokens-3-5-sonnet-2024-07-15",

# https://www.anthropic.com/news/prompt-caching
"prompt-caching-2024-07-31",
}.join(','),
}

def create(
*,
model : String,
Expand All @@ -29,19 +45,10 @@ module Anthropic
tools: tools.to_json,
)

headers = HTTP::Headers.new

# 3.5 Sonnet only supports 4k tokens by default, but you can opt into
# up to 8k output tokens.
# https://x.com/alexalbert__/status/1812921642143900036
if model.includes?("3-5-sonnet") && max_tokens > 4096
headers.add "anthropic-beta", "max-tokens-3-5-sonnet-2024-07-15"
end

# TODO: Investigate whether the `beta=tools` is needed since we're using
# the tools beta header above.
response = client.post "/v1/messages?beta=tools",
headers: headers,
headers: CREATE_HEADERS,
body: request,
as: GeneratedMessage
response.message_thread = messages.dup << response.to_message
Expand Down

0 comments on commit 841613b

Please sign in to comment.