@@ -1435,43 +1435,78 @@ export class Task extends EventEmitter<ClineEvents> {
14351435 }
14361436
14371437 const drainStreamInBackgroundToFindAllUsage = async ( ) => {
1438- let usageFound = false
1439- while ( ! item . done ) {
1440- const chunk = item . value
1441- item = await iterator . next ( )
1442- if ( chunk && chunk . type === "usage" ) {
1443- usageFound = true
1444- inputTokens += chunk . inputTokens
1445- outputTokens += chunk . outputTokens
1446- cacheWriteTokens += chunk . cacheWriteTokens ?? 0
1447- cacheReadTokens += chunk . cacheReadTokens ?? 0
1448- totalCost = chunk . totalCost
1438+ const timeoutMs = 30000 // 30 second timeout
1439+ const startTime = Date . now ( )
1440+
1441+ try {
1442+ let usageFound = false
1443+ while ( ! item . done ) {
1444+ // Check for timeout
1445+ if ( Date . now ( ) - startTime > timeoutMs ) {
1446+ console . warn ( `Background usage collection timed out after ${ timeoutMs } ms` )
1447+ break
1448+ }
1449+
1450+ const chunk = item . value
1451+ item = await iterator . next ( )
1452+ if ( chunk && chunk . type === "usage" ) {
1453+ usageFound = true
1454+ inputTokens += chunk . inputTokens
1455+ outputTokens += chunk . outputTokens
1456+ cacheWriteTokens += chunk . cacheWriteTokens ?? 0
1457+ cacheReadTokens += chunk . cacheReadTokens ?? 0
1458+ totalCost = chunk . totalCost
1459+ }
1460+ }
1461+ if ( usageFound ) {
1462+ updateApiReqMsg ( )
1463+ await this . saveClineMessages ( )
1464+ }
1465+ if ( inputTokens > 0 || outputTokens > 0 || cacheWriteTokens > 0 || cacheReadTokens > 0 ) {
1466+ TelemetryService . instance . captureLlmCompletion ( this . taskId , {
1467+ inputTokens,
1468+ outputTokens,
1469+ cacheWriteTokens,
1470+ cacheReadTokens,
1471+ cost :
1472+ totalCost ??
1473+ calculateApiCostAnthropic (
1474+ this . api . getModel ( ) . info ,
1475+ inputTokens ,
1476+ outputTokens ,
1477+ cacheWriteTokens ,
1478+ cacheReadTokens ,
1479+ ) ,
1480+ } )
1481+ } else {
1482+ const modelId = getModelId ( this . apiConfiguration )
1483+ console . warn (
1484+ `Suspicious: request ${ lastApiReqIndex } is complete, but no usage info was found. Model: ${ modelId } ` ,
1485+ )
1486+ }
1487+ } catch ( error ) {
1488+ console . error ( "Error draining stream for usage data:" , error )
1489+ // Still try to capture whatever usage data we have collected so far
1490+ if ( inputTokens > 0 || outputTokens > 0 || cacheWriteTokens > 0 || cacheReadTokens > 0 ) {
1491+ TelemetryService . instance . captureLlmCompletion ( this . taskId , {
1492+ inputTokens,
1493+ outputTokens,
1494+ cacheWriteTokens,
1495+ cacheReadTokens,
1496+ cost :
1497+ totalCost ??
1498+ calculateApiCostAnthropic (
1499+ this . api . getModel ( ) . info ,
1500+ inputTokens ,
1501+ outputTokens ,
1502+ cacheWriteTokens ,
1503+ cacheReadTokens ,
1504+ ) ,
1505+ } )
14491506 }
1450- }
1451- if ( usageFound ) {
1452- updateApiReqMsg ( )
1453- }
1454- if ( inputTokens > 0 || outputTokens > 0 || cacheWriteTokens > 0 || cacheReadTokens > 0 ) {
1455- TelemetryService . instance . captureLlmCompletion ( this . taskId , {
1456- inputTokens,
1457- outputTokens,
1458- cacheWriteTokens,
1459- cacheReadTokens,
1460- cost :
1461- totalCost ??
1462- calculateApiCostAnthropic (
1463- this . api . getModel ( ) . info ,
1464- inputTokens ,
1465- outputTokens ,
1466- cacheWriteTokens ,
1467- cacheReadTokens ,
1468- ) ,
1469- } )
1470- } else {
1471- console . warn ( `Suspicious: request ${ lastApiReqIndex } is complete, but no usage info was found.` )
14721507 }
14731508 }
1474- drainStreamInBackgroundToFindAllUsage ( ) // no await so it runs in the background
1509+ const backgroundDrainPromise = drainStreamInBackgroundToFindAllUsage ( ) // Store promise reference
14751510 } catch ( error ) {
14761511 // Abandoned happens when extension is no longer waiting for the
14771512 // Cline instance to finish aborting (error is thrown here when
@@ -1534,7 +1569,8 @@ export class Task extends EventEmitter<ClineEvents> {
15341569 presentAssistantMessage ( this )
15351570 }
15361571
1537- updateApiReqMsg ( )
1572+ // Note: updateApiReqMsg() is now called from within drainStreamInBackgroundToFindAllUsage
1573+ // to avoid race conditions with the background task
15381574 await this . saveClineMessages ( )
15391575 await this . providerRef . deref ( ) ?. postStateToWebview ( )
15401576
0 commit comments