approximateMessageBreakdown method
Approximate token usage by message type.
Implementation
MessageBreakdown approximateMessageBreakdown(
List<Map<String, dynamic>> messages,
) {
final breakdown = _MutableMessageBreakdown();
final toolUseIdToName = <String, String>{};
// Build tool_use_id to name map
for (final msg in messages) {
if (msg['type'] == 'assistant') {
final content = msg['content'] as List<dynamic>? ?? [];
for (final block in content) {
if (block is Map && block['type'] == 'tool_use') {
final id = block['id'] as String?;
final name = block['name'] as String? ?? 'unknown';
if (id != null) toolUseIdToName[id] = name;
}
}
}
}
for (final msg in messages) {
final type = msg['type'] as String?;
if (type == 'assistant') {
final content = msg['content'] as List<dynamic>? ?? [];
for (final block in content) {
if (block is Map) {
final blockStr = block.toString();
final blockTokens = _roughTokenCountEstimation(blockStr);
if (block['type'] == 'tool_use') {
breakdown.toolCallTokens += blockTokens;
final toolName = block['name'] as String? ?? 'unknown';
breakdown.toolCallsByType[toolName] =
(breakdown.toolCallsByType[toolName] ?? 0) + blockTokens;
} else {
breakdown.assistantMessageTokens += blockTokens;
}
}
}
} else if (type == 'user') {
final content = msg['content'];
if (content is String) {
breakdown.userMessageTokens += _roughTokenCountEstimation(content);
} else if (content is List) {
for (final block in content) {
if (block is Map) {
final blockStr = block.toString();
final blockTokens = _roughTokenCountEstimation(blockStr);
if (block['type'] == 'tool_result') {
breakdown.toolResultTokens += blockTokens;
final toolUseId = block['tool_use_id'] as String?;
final toolName =
(toolUseId != null ? toolUseIdToName[toolUseId] : null) ??
'unknown';
breakdown.toolResultsByType[toolName] =
(breakdown.toolResultsByType[toolName] ?? 0) + blockTokens;
} else {
breakdown.userMessageTokens += blockTokens;
}
}
}
}
} else if (type == 'attachment') {
final attachment = msg['attachment'] as Map<String, dynamic>?;
if (attachment != null) {
final tokens = _roughTokenCountEstimation(attachment.toString());
breakdown.attachmentTokens += tokens;
final attachType = attachment['type'] as String? ?? 'unknown';
breakdown.attachmentsByType[attachType] =
(breakdown.attachmentsByType[attachType] ?? 0) + tokens;
}
}
}
breakdown.totalTokens =
breakdown.toolCallTokens +
breakdown.toolResultTokens +
breakdown.attachmentTokens +
breakdown.assistantMessageTokens +
breakdown.userMessageTokens;
// Convert to sorted lists
final toolCallsByType =
breakdown.toolCallsByType.entries
.map(
(e) => ToolCallsByType(
name: e.key,
callTokens: e.value,
resultTokens: breakdown.toolResultsByType[e.key] ?? 0,
),
)
.toList()
..sort(
(a, b) =>
(b.callTokens + b.resultTokens) -
(a.callTokens + a.resultTokens),
);
final attachmentsByType =
breakdown.attachmentsByType.entries
.map((e) => AttachmentsByType(name: e.key, tokens: e.value))
.toList()
..sort((a, b) => b.tokens - a.tokens);
return MessageBreakdown(
toolCallTokens: breakdown.toolCallTokens,
toolResultTokens: breakdown.toolResultTokens,
attachmentTokens: breakdown.attachmentTokens,
assistantMessageTokens: breakdown.assistantMessageTokens,
userMessageTokens: breakdown.userMessageTokens,
toolCallsByType: toolCallsByType,
attachmentsByType: attachmentsByType,
);
}