sendMessage method

  1. @override
Future<String> sendMessage({
  1. required String systemPrompt,
  2. required List<Map<String, String>> messages,
  3. int maxTokens = 8192,
})
override

Send messages to the Claude Messages API and return the assistant text.

Implementation

@override
Future<String> sendMessage({
  required String systemPrompt,
  required List<Map<String, String>> messages,
  int maxTokens = 8192,
}) async {
  final apiKey = await _getApiKey();
  if (apiKey == null || apiKey.isEmpty) {
    throw Exception('Claude API key is not configured.');
  }

  final model = await _getModel();

  dev.log(
    'Claude API request: model=$model, '
    'systemPrompt=${systemPrompt.length} chars, '
    'messages=${messages.length}, '
    'maxTokens=$maxTokens, '
    'apiVersion=${AiProviderConfig.claudeApiVersion}',
    name: 'ClaudeDatasource',
  );

  try {
    final response = await _dio.post(
      _provider.apiUrl,
      options: Options(
        headers: {
          'x-api-key': apiKey,
          'anthropic-version': AiProviderConfig.claudeApiVersion,
          'content-type': 'application/json',
        },
      ),
      data: {
        'model': model,
        'max_tokens': maxTokens,
        'system': [
          {
            'type': 'text',
            'text': systemPrompt,
            'cache_control': {'type': 'ephemeral'},
          },
        ],
        'messages': messages,
      },
    );

    final data = response.data as Map<String, dynamic>;
    final content = data['content'] as List<dynamic>;
    // Extract the first text block.
    for (final block in content) {
      final blockMap = block as Map<String, dynamic>;
      if (blockMap['type'] == 'text') {
        return blockMap['text'] as String;
      }
    }
    throw Exception('No text content in Claude API response.');
  } on DioException catch (e) {
    throw _mapDioError(e);
  }
}