Skip to content

Commit eca7395

Browse files
committed
fix: map token usage metadata for Anthropic Claude model
1 parent fb9274e commit eca7395

2 files changed

Lines changed: 32 additions & 5 deletions

File tree

core/src/main/java/com/google/adk/models/Claude.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,7 @@
3434
import com.google.adk.JsonBaseModel;
3535
import com.google.common.collect.ImmutableList;
3636
import com.google.common.collect.ImmutableMap;
37-
import com.google.genai.types.Content;
38-
import com.google.genai.types.FunctionCall;
39-
import com.google.genai.types.FunctionDeclaration;
40-
import com.google.genai.types.GenerateContentConfig;
41-
import com.google.genai.types.Part;
37+
import com.google.genai.types.*;
4238
import io.reactivex.rxjava3.core.Flowable;
4339
import java.util.ArrayList;
4440
import java.util.HashMap;
@@ -268,6 +264,15 @@ private LlmResponse convertAnthropicResponseToLlmResponse(Message message) {
268264
responseBuilder.content(
269265
Content.builder().role("model").parts(ImmutableList.copyOf(parts)).build());
270266
}
267+
if (message.usage() != null) {
268+
responseBuilder.usageMetadata(
269+
GenerateContentResponseUsageMetadata.builder()
270+
.promptTokenCount((int) message.usage().inputTokens())
271+
.candidatesTokenCount((int) message.usage().outputTokens())
272+
.totalTokenCount(
273+
(int) (message.usage().inputTokens() + message.usage().outputTokens()))
274+
.build());
275+
}
271276
return responseBuilder.build();
272277
}
273278

core/src/test/java/com/google/adk/models/ClaudeTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,15 @@
1717
package com.google.adk.models;
1818

1919
import static com.google.common.truth.Truth.assertThat;
20+
import static org.junit.jupiter.api.Assertions.assertTrue;
21+
import static org.mockito.Mockito.mock;
22+
import static org.mockito.Mockito.when;
2023

2124
import com.anthropic.client.AnthropicClient;
2225
import com.anthropic.models.messages.ContentBlockParam;
26+
import com.anthropic.models.messages.Message;
2327
import com.anthropic.models.messages.ToolResultBlockParam;
28+
import com.anthropic.models.messages.Usage;
2429
import com.google.common.collect.ImmutableMap;
2530
import com.google.genai.types.FunctionResponse;
2631
import com.google.genai.types.Part;
@@ -78,4 +83,21 @@ public void testPartToAnthropicMessageBlock_jsonFallback() throws Exception {
7883
ToolResultBlockParam toolResult = result.asToolResult();
7984
assertThat(toolResult.content().get().asString()).contains("\"custom_key\":\"custom_value\"");
8085
}
86+
87+
@Test
88+
public void testClaudeUsageMapping_ShouldFailWhenMappingIsMissing() throws Exception {
89+
Usage mockUsage = mock(Usage.class);
90+
when(mockUsage.inputTokens()).thenReturn(10L);
91+
when(mockUsage.outputTokens()).thenReturn(20L);
92+
93+
Message mockMessage = mock(Message.class);
94+
when(mockMessage.usage()).thenReturn(mockUsage);
95+
when(mockMessage.content()).thenReturn(java.util.Collections.emptyList());
96+
97+
Method convertMethod =
98+
Claude.class.getDeclaredMethod("convertAnthropicResponseToLlmResponse", Message.class);
99+
convertMethod.setAccessible(true);
100+
LlmResponse result = (LlmResponse) convertMethod.invoke(claude, mockMessage);
101+
assertTrue(result.usageMetadata().isPresent());
102+
}
81103
}

0 commit comments

Comments
 (0)