@@ -43,6 +43,7 @@ type AnthropicMessageLike = {
4343 content ?: Array < any > ;
4444 stop_reason ?: string | null ;
4545 parsed_output ?: unknown ;
46+ usage ?: AnthropicUsage ;
4647} ;
4748
4849type AnthropicToolUseBlock = {
@@ -67,6 +68,19 @@ type LangChainModelCallRequest = {
6768 messages : LangChainMessageLike [ ] ;
6869} ;
6970
71+ type AnthropicUsage = {
72+ input_tokens ?: number ;
73+ cache_creation_input_tokens ?: number | null ;
74+ cache_read_input_tokens ?: number | null ;
75+ output_tokens ?: number ;
76+ } ;
77+
78+ type UsedTokens = {
79+ input_uncached : number ;
80+ input_cached : number ;
81+ output : number ;
82+ } ;
83+
7084function getApiKey ( options : AdapterOptions ) : string | undefined {
7185 return options . anthropicApiKey || options . antropicApiKey ;
7286}
@@ -112,6 +126,21 @@ function extractReasoning(data: AnthropicMessageLike): string | undefined {
112126 return reasoning || undefined ;
113127}
114128
129+ function extractUsedTokens ( data : AnthropicMessageLike ) : UsedTokens | undefined {
130+ const usage = data . usage ;
131+ if ( ! usage ) return undefined ;
132+
133+ const inputTokens = usage . input_tokens ?? 0 ;
134+ const cacheWriteTokens = usage . cache_creation_input_tokens ?? 0 ;
135+ const cacheReadTokens = usage . cache_read_input_tokens ?? 0 ;
136+
137+ return {
138+ input_uncached : inputTokens + cacheWriteTokens ,
139+ input_cached : cacheReadTokens ,
140+ output : usage . output_tokens ?? 0 ,
141+ } ;
142+ }
143+
115144function extractToolUse ( data : AnthropicMessageLike ) : AnthropicToolUseBlock | undefined {
116145 for ( const block of data . content ?? [ ] ) {
117146 if ( block ?. type === "tool_use" ) {
@@ -323,6 +352,7 @@ export default class CompletionAdapterAnthropicMessages
323352 content ?: string ;
324353 finishReason ?: string ;
325354 error ?: string ;
355+ used_tokens ?: UsedTokens ;
326356 } > => {
327357 const request =
328358 typeof requestOrContent === "string"
@@ -386,6 +416,7 @@ export default class CompletionAdapterAnthropicMessages
386416 ? extractOutputText ( parsedMessage )
387417 : JSON . stringify ( parsedMessage . parsed_output ) ;
388418 const parsedReasoning = extractReasoning ( parsedMessage ) ;
419+ const usedTokens = extractUsedTokens ( parsedMessage ) ;
389420
390421 if ( parsedReasoning && isStreaming ) {
391422 await streamChunkCallback ?.( parsedReasoning , {
@@ -417,25 +448,29 @@ export default class CompletionAdapterAnthropicMessages
417448 return {
418449 content : toolResult ,
419450 finishReason : "tool_call" ,
451+ used_tokens : usedTokens ,
420452 } ;
421453 } catch ( error ) {
422454 return {
423455 error : getErrorMessage ( error ) ,
424456 finishReason : "tool_call" ,
457+ used_tokens : usedTokens ,
425458 } ;
426459 }
427460 }
428461
429462 return {
430463 content : parsedOutput || undefined ,
431464 finishReason : parsedMessage . stop_reason || undefined ,
465+ used_tokens : usedTokens ,
432466 } ;
433467 }
434468
435469 if ( ! isStreaming ) {
436470 const message = ( await this . getClient ( ) . messages . create (
437471 body as any ,
438472 ) ) as AnthropicMessageLike ;
473+ const usedTokens = extractUsedTokens ( message ) ;
439474
440475 const toolUse = extractToolUse ( message ) ;
441476 if ( toolUse ) {
@@ -444,18 +479,21 @@ export default class CompletionAdapterAnthropicMessages
444479 return {
445480 content : toolResult ,
446481 finishReason : "tool_call" ,
482+ used_tokens : usedTokens ,
447483 } ;
448484 } catch ( error ) {
449485 return {
450486 error : getErrorMessage ( error ) ,
451487 finishReason : "tool_call" ,
488+ used_tokens : usedTokens ,
452489 } ;
453490 }
454491 }
455492
456493 return {
457494 content : extractOutputText ( message ) || undefined ,
458495 finishReason : message . stop_reason || undefined ,
496+ used_tokens : usedTokens ,
459497 } ;
460498 }
461499
@@ -492,6 +530,7 @@ export default class CompletionAdapterAnthropicMessages
492530 const message = ( await stream . finalMessage ( ) ) as AnthropicMessageLike ;
493531 const finalContent = extractOutputText ( message ) ;
494532 const finalReasoning = extractReasoning ( message ) || "" ;
533+ const usedTokens = extractUsedTokens ( message ) ;
495534
496535 if ( finalReasoning && finalReasoning !== fullReasoning ) {
497536 const delta = finalReasoning . startsWith ( fullReasoning )
@@ -541,19 +580,22 @@ export default class CompletionAdapterAnthropicMessages
541580 return {
542581 content : toolResult ,
543582 finishReason : "tool_call" ,
583+ used_tokens : usedTokens ,
544584 } ;
545585 } catch ( error ) {
546586 return {
547587 error : getErrorMessage ( error ) ,
548588 content : fullContent || undefined ,
549589 finishReason : "tool_call" ,
590+ used_tokens : usedTokens ,
550591 } ;
551592 }
552593 }
553594
554595 return {
555596 content : fullContent || undefined ,
556597 finishReason : message . stop_reason || undefined ,
598+ used_tokens : usedTokens ,
557599 } ;
558600 } catch ( error ) {
559601 return {
0 commit comments