@@ -7,6 +7,7 @@ import (
77 "fmt"
88 "io"
99 "log/slog"
10+ "strings"
1011 "time"
1112
1213 "github.com/charmbracelet/catwalk/pkg/catwalk"
@@ -56,14 +57,33 @@ func createOpenAIClient(opts providerClientOptions) openai.Client {
5657}
5758
5859func (o *openaiClient) convertMessages(messages []message.Message) (openaiMessages []openai.ChatCompletionMessageParamUnion) {
60+ isAnthropicModel := o.providerOptions.config.ID == "openrouter" && strings.HasPrefix(o.Model().ID, "anthropic/")
5961 // Add system message first
6062 systemMessage := o.providerOptions.systemMessage
6163 if o.providerOptions.systemPromptPrefix != "" {
6264 systemMessage = o.providerOptions.systemPromptPrefix + "\n" + systemMessage
6365 }
64− openaiMessages = append(openaiMessages, openai.SystemMessage(systemMessage))
6566
66− for _, msg := range messages {
67+ systemTextBlock := openai.ChatCompletionContentPartTextParam{Text: systemMessage}
68+ if isAnthropicModel && !o.providerOptions.disableCache {
69+ systemTextBlock.SetExtraFields(
70+ map[string]any{
71+ "cache_control": map[string]string{
72+ "type": "ephemeral",
73+ },
74+ },
75+ )
76+ }
77+ var content []openai.ChatCompletionContentPartTextParam
78+ content = append(content, systemTextBlock)
79+ system := openai.SystemMessage(content)
80+ openaiMessages = append(openaiMessages, system)
81+
82+ for i, msg := range messages {
83+ cache := false
84+ if i > len(messages)-3 {
85+ cache = true
86+ }
6787 switch msg.Role {
6888 case message.User:
6989 var content []openai.ChatCompletionContentPartUnionParam
@@ -75,6 +95,13 @@ func (o *openaiClient) convertMessages(messages []message.Message) (openaiMessag
7595
7696 content = append(content, openai.ChatCompletionContentPartUnionParam{OfImageURL: &imageBlock})
7797 }
98+ if cache && !o.providerOptions.disableCache && isAnthropicModel {
99+ textBlock.SetExtraFields(map[string]any{
100+ "cache_control": map[string]string{
101+ "type": "ephemeral",
102+ },
103+ })
104+ }
78105
79106 openaiMessages = append(openaiMessages, openai.UserMessage(content))
80107
@@ -86,8 +113,20 @@ func (o *openaiClient) convertMessages(messages []message.Message) (openaiMessag
86113 hasContent := false
87114 if msg.Content().String() != "" {
88115 hasContent = true
116+ textBlock := openai.ChatCompletionContentPartTextParam{Text: msg.Content().String()}
117+ if cache && !o.providerOptions.disableCache && isAnthropicModel {
118+ textBlock.SetExtraFields(map[string]any{
119+ "cache_control": map[string]string{
120+ "type": "ephemeral",
121+ },
122+ })
123+ }
89124 assistantMsg.Content = openai.ChatCompletionAssistantMessageParamContentUnion{
90− OfString: openai.String(msg.Content().String()),
125+ OfArrayOfContentParts: []openai.ChatCompletionAssistantMessageParamContentArrayOfContentPartUnion{
126+ {
127+ OfText: &textBlock,
128+ },
129+ },
91130 }
92131 }
93132