@@ -55,9 +55,12 @@ func (h *Handler) messagesHandler(c *gin.Context) {
5555
5656 // Input token counting + prompt-cache simulation.
5757 inputTokens := util .CountMessagesTokens (apiReq .Messages )
58+ cacheCreation , cacheRead := util .RecordAnthropicCache (req )
5859 promptHash := util .HashPrompt (messagesText (apiReq .Messages ))
59- cacheCreation , cacheRead := util .RecordCache (promptHash , inputTokens )
60- cachedTokens := cacheRead
60+ if cacheCreation == 0 && cacheRead == 0 {
61+ // Fallback to prompt hash simulation if request has no explicit cache_control blocks
62+ cacheCreation , cacheRead = util .RecordCache (promptHash , inputTokens )
63+ }
6164
6265 translated , response , err := h .startDuckDuckGoRequest (apiReq )
6366 if err != nil {
@@ -77,11 +80,10 @@ func (h *Handler) messagesHandler(c *gin.Context) {
7780 }
7881
7982 // Cache breakdown is known before streaming; set before first flush.
80- c .Header ("X-Cache-Creation-Tokens" , fmt .Sprintf ("%d" , cacheCreation ))
81- c .Header ("X-Cache-Read-Tokens" , fmt .Sprintf ("%d" , cacheRead ))
83+ setCacheHeaders (c , promptHash , cacheCreation , cacheRead )
8284
8385 start := time .Now ()
84- result := handleAnthropicStream (c , response .Body , req .Model , req .Stream , start , inputTokens , cachedTokens , effort )
86+ result := handleAnthropicStream (c , response .Body , req .Model , req .Stream , start , inputTokens , cacheCreation , cacheRead , effort )
8587
8688 // Timing headers (only delivered for non-stream; for stream the same values
8789 // live in the message_delta event).
@@ -93,13 +95,13 @@ func (h *Handler) messagesHandler(c *gin.Context) {
9395 }
9496
9597 if ! req .Stream {
96- c .JSON (200 , buildAnthropicResponse (req .Model , result , inputTokens , cachedTokens , effort ))
98+ c .JSON (200 , buildAnthropicResponse (req .Model , result , inputTokens , cacheCreation , cacheRead , effort ))
9799 }
98100}
99101
100102// handleAnthropicStream reads DuckDuckGo's text SSE and emits Anthropic SSE events.
101103// For non-stream it accumulates the text and returns the result.
102- func handleAnthropicStream (c * gin.Context , body io.ReadCloser , model string , stream bool , start time.Time , inputTokens , cachedTokens int , effort string ) anthropicStreamResult {
104+ func handleAnthropicStream (c * gin.Context , body io.ReadCloser , model string , stream bool , start time.Time , inputTokens , cacheCreation , cacheRead int , effort string ) anthropicStreamResult {
103105 defer body .Close ()
104106
105107 reader := bufio .NewReader (body )
@@ -124,7 +126,11 @@ func handleAnthropicStream(c *gin.Context, body io.ReadCloser, model string, str
124126 Role : "assistant" ,
125127 Model : model ,
126128 Content : []anthropic.ContentBlock {},
127- Usage : anthropic.AnthropicUsage {InputTokens : inputTokens },
129+ Usage : anthropic.AnthropicUsage {
130+ InputTokens : inputTokens ,
131+ CacheCreationInputTokens : cacheCreation ,
132+ CacheReadInputTokens : cacheRead ,
133+ },
128134 },
129135 })
130136 writeEvent (c , "content_block_start" , anthropic.ContentBlockStartEvent {
@@ -210,13 +216,12 @@ func writeEvent(c *gin.Context, eventType string, payload interface{}) {
210216}
211217
212218// buildAnthropicResponse builds the non-stream MessagesResponse.
213- func buildAnthropicResponse (model string , r anthropicStreamResult , inputTokens , cachedTokens int , effort string ) anthropic.MessagesResponse {
219+ func buildAnthropicResponse (model string , r anthropicStreamResult , inputTokens , cacheCreation , cacheRead int , effort string ) anthropic.MessagesResponse {
214220 usage := anthropic.AnthropicUsage {
215- InputTokens : inputTokens ,
216- OutputTokens : r .outputTokens ,
217- }
218- if cachedTokens > 0 {
219- usage .CacheReadInputTokens = cachedTokens
221+ InputTokens : inputTokens ,
222+ OutputTokens : r .outputTokens ,
223+ CacheCreationInputTokens : cacheCreation ,
224+ CacheReadInputTokens : cacheRead ,
220225 }
221226 return anthropic.MessagesResponse {
222227 ID : "msg_" + util .RandomHexadecimalString (),
0 commit comments