@@ -14,7 +14,11 @@ import type {
1414 ProviderResponse ,
1515 TimeSegment ,
1616} from '@/providers/types'
17- import { prepareToolExecution , prepareToolsWithUsageControl } from '@/providers/utils'
17+ import {
18+ calculateCost ,
19+ prepareToolExecution ,
20+ prepareToolsWithUsageControl ,
21+ } from '@/providers/utils'
1822import { executeTool } from '@/tools'
1923
2024const logger = createLogger ( 'AnthropicProvider' )
@@ -255,28 +259,49 @@ ${fieldDescriptions}
255259 const providerStartTime = Date . now ( )
256260 const providerStartTimeISO = new Date ( providerStartTime ) . toISOString ( )
257261
258- // Create a streaming request
259262 const streamResponse : any = await anthropic . messages . create ( {
260263 ...payload ,
261264 stream : true ,
262265 } )
263266
264- // Start collecting token usage
265- const tokenUsage = {
266- prompt : 0 ,
267- completion : 0 ,
268- total : 0 ,
269- }
270-
271- // Create a StreamingExecution response with a readable stream
272267 const streamingResult = {
273- stream : createReadableStreamFromAnthropicStream ( streamResponse ) ,
268+ stream : createReadableStreamFromAnthropicStream ( streamResponse , ( content , usage ) => {
269+ streamingResult . execution . output . content = content
270+ streamingResult . execution . output . tokens = {
271+ prompt : usage . input_tokens ,
272+ completion : usage . output_tokens ,
273+ total : usage . input_tokens + usage . output_tokens ,
274+ }
275+
276+ const costResult = calculateCost ( request . model , usage . input_tokens , usage . output_tokens )
277+ streamingResult . execution . output . cost = {
278+ input : costResult . input ,
279+ output : costResult . output ,
280+ total : costResult . total ,
281+ }
282+
283+ const streamEndTime = Date . now ( )
284+ const streamEndTimeISO = new Date ( streamEndTime ) . toISOString ( )
285+
286+ if ( streamingResult . execution . output . providerTiming ) {
287+ streamingResult . execution . output . providerTiming . endTime = streamEndTimeISO
288+ streamingResult . execution . output . providerTiming . duration =
289+ streamEndTime - providerStartTime
290+
291+ if ( streamingResult . execution . output . providerTiming . timeSegments ?. [ 0 ] ) {
292+ streamingResult . execution . output . providerTiming . timeSegments [ 0 ] . endTime =
293+ streamEndTime
294+ streamingResult . execution . output . providerTiming . timeSegments [ 0 ] . duration =
295+ streamEndTime - providerStartTime
296+ }
297+ }
298+ } ) ,
274299 execution : {
275300 success : true ,
276301 output : {
277- content : '' , // Will be filled by streaming content in chat component
302+ content : '' ,
278303 model : request . model ,
279- tokens : tokenUsage ,
304+ tokens : { prompt : 0 , completion : 0 , total : 0 } ,
280305 toolCalls : undefined ,
281306 providerTiming : {
282307 startTime : providerStartTimeISO ,
@@ -292,14 +317,13 @@ ${fieldDescriptions}
292317 } ,
293318 ] ,
294319 } ,
295- // Estimate token cost based on typical Claude pricing
296320 cost : {
297321 total : 0.0 ,
298322 input : 0.0 ,
299323 output : 0.0 ,
300324 } ,
301325 } ,
302- logs : [ ] , // No block logs for direct streaming
326+ logs : [ ] ,
303327 metadata : {
304328 startTime : providerStartTimeISO ,
305329 endTime : new Date ( ) . toISOString ( ) ,
@@ -309,7 +333,6 @@ ${fieldDescriptions}
309333 } ,
310334 }
311335
312- // Return the streaming execution object
313336 return streamingResult as StreamingExecution
314337 }
315338
@@ -688,6 +711,17 @@ ${fieldDescriptions}
688711 ( currentResponse . usage ?. input_tokens || 0 ) + ( currentResponse . usage ?. output_tokens || 0 ) ,
689712 }
690713
714+ const initialCost = calculateCost (
715+ request . model ,
716+ currentResponse . usage ?. input_tokens || 0 ,
717+ currentResponse . usage ?. output_tokens || 0
718+ )
719+ const cost = {
720+ input : initialCost . input ,
721+ output : initialCost . output ,
722+ total : initialCost . total ,
723+ }
724+
691725 const toolCalls = [ ]
692726 const toolResults = [ ]
693727 const currentMessages = [ ...messages ]
@@ -899,12 +933,21 @@ ${fieldDescriptions}
899933 content = textContent
900934 }
901935
902- // Update token counts
936+ // Update token counts and cost
903937 if ( currentResponse . usage ) {
904938 tokens . prompt += currentResponse . usage . input_tokens || 0
905939 tokens . completion += currentResponse . usage . output_tokens || 0
906940 tokens . total +=
907941 ( currentResponse . usage . input_tokens || 0 ) + ( currentResponse . usage . output_tokens || 0 )
942+
943+ const iterationCost = calculateCost (
944+ request . model ,
945+ currentResponse . usage . input_tokens || 0 ,
946+ currentResponse . usage . output_tokens || 0
947+ )
948+ cost . input += iterationCost . input
949+ cost . output += iterationCost . output
950+ cost . total += iterationCost . total
908951 }
909952
910953 iterationCount ++
@@ -931,31 +974,47 @@ ${fieldDescriptions}
931974 const providerEndTimeISO = new Date ( providerEndTime ) . toISOString ( )
932975 const totalDuration = providerEndTime - providerStartTime
933976
934- // After all tool processing complete, if streaming was requested, use streaming for the final response
935977 if ( request . stream ) {
936978 logger . info ( 'Using streaming for final Anthropic response after tool processing' )
937979
938- // When streaming after tool calls with forced tools, make sure tool_choice is removed
939- // This prevents the API from trying to force tool usage again in the final streaming response
940980 const streamingPayload = {
941981 ...payload ,
942982 messages : currentMessages ,
943- // For Anthropic, omit tool_choice entirely rather than setting it to 'none'
944983 stream : true ,
984+ tool_choice : undefined ,
945985 }
946986
947- // Remove the tool_choice parameter as Anthropic doesn't accept 'none' as a string value
948- streamingPayload . tool_choice = undefined
949-
950987 const streamResponse : any = await anthropic . messages . create ( streamingPayload )
951988
952- // Create a StreamingExecution response with all collected data
953989 const streamingResult = {
954- stream : createReadableStreamFromAnthropicStream ( streamResponse ) ,
990+ stream : createReadableStreamFromAnthropicStream ( streamResponse , ( content , usage ) => {
991+ streamingResult . execution . output . content = content
992+ streamingResult . execution . output . tokens = {
993+ prompt : tokens . prompt + usage . input_tokens ,
994+ completion : tokens . completion + usage . output_tokens ,
995+ total : tokens . total + usage . input_tokens + usage . output_tokens ,
996+ }
997+
998+ const streamCost = calculateCost ( request . model , usage . input_tokens , usage . output_tokens )
999+ streamingResult . execution . output . cost = {
1000+ input : cost . input + streamCost . input ,
1001+ output : cost . output + streamCost . output ,
1002+ total : cost . total + streamCost . total ,
1003+ }
1004+
1005+ const streamEndTime = Date . now ( )
1006+ const streamEndTimeISO = new Date ( streamEndTime ) . toISOString ( )
1007+
1008+ if ( streamingResult . execution . output . providerTiming ) {
1009+ streamingResult . execution . output . providerTiming . endTime = streamEndTimeISO
1010+ streamingResult . execution . output . providerTiming . duration =
1011+ streamEndTime - providerStartTime
1012+ }
1013+ } ) ,
9551014 execution : {
9561015 success : true ,
9571016 output : {
958- content : '' , // Will be filled by the callback
1017+ content : '' ,
9591018 model : request . model || 'claude-3-7-sonnet-20250219' ,
9601019 tokens : {
9611020 prompt : tokens . prompt ,
@@ -980,12 +1039,12 @@ ${fieldDescriptions}
9801039 timeSegments : timeSegments ,
9811040 } ,
9821041 cost : {
983- total : ( tokens . total || 0 ) * 0.0001 , // Estimate cost based on tokens
984- input : ( tokens . prompt || 0 ) * 0.0001 ,
985- output : ( tokens . completion || 0 ) * 0.0001 ,
1042+ input : cost . input ,
1043+ output : cost . output ,
1044+ total : cost . total ,
9861045 } ,
9871046 } ,
988- logs : [ ] , // No block logs at provider level
1047+ logs : [ ] ,
9891048 metadata : {
9901049 startTime : providerStartTimeISO ,
9911050 endTime : new Date ( ) . toISOString ( ) ,
0 commit comments