build method
Implementation
ChatMessage build() {
// Create universal text content, excluding tools blocks and empty text blocks
final textBlocks = _blocks.where(
(block) => block is! ToolsBlock && block.displayText.trim().isNotEmpty);
final content = textBlocks.map((block) => block.displayText).join('\n');
// Group blocks by provider
final extensions = <String, dynamic>{};
final providerGroups = <String, List<ContentBlock>>{};
final universalTools = <ToolsBlock>[];
for (final block in _blocks) {
if (block.providerId == 'universal') {
// Special handling for ToolsBlock - they might need to be moved to anthropic extension
if (block is ToolsBlock) {
universalTools.add(block);
}
continue;
}
providerGroups.putIfAbsent(block.providerId, () => []).add(block);
}
// Check if we have Anthropic cache markers and tools that need to be combined
if (providerGroups.containsKey('anthropic') && universalTools.isNotEmpty) {
final anthropicBlocks = providerGroups['anthropic']!;
// Check if there's a cache marker (empty text block with cache_control)
final hasCacheMarker = anthropicBlocks.any((block) {
final json = block.toJson();
return json['cache_control'] != null && json['text'] == '';
});
if (hasCacheMarker) {
// Move tools to anthropic extension for caching
// Create AnthropicToolsBlock from universal ToolsBlock
for (final toolsBlock in universalTools) {
// Create a new block that will be treated as anthropic-specific
final anthropicToolsBlock =
_AnthropicToolsBlockWrapper(toolsBlock.tools);
anthropicBlocks.add(anthropicToolsBlock);
}
}
}
// Create extensions for each provider
for (final entry in providerGroups.entries) {
extensions[entry.key] = {
'contentBlocks': entry.value.map((block) => block.toJson()).toList(),
};
}
return ChatMessage(
role: _role,
messageType: const TextMessage(),
content: content,
name: _name,
extensions: extensions,
);
}