convertMessage method

Map<String, dynamic> convertMessage(
  1. ChatMessage message
)

Convert ChatMessage to OpenAI API format

Implementation

Map<String, dynamic> convertMessage(ChatMessage message) {
  final result = <String, dynamic>{'role': message.role.name};

  // Add name field if present (useful for system messages)
  if (message.name != null) {
    result['name'] = message.name;
  }

  switch (message.messageType) {
    case TextMessage():
      result['content'] = message.content;
      break;
    case ImageMessage(mime: final mime, data: final data):
      // Handle base64 encoded images
      final base64Data = base64Encode(data);
      final imageDataUrl = 'data:${mime.mimeType};base64,$base64Data';

      // Build content array with optional text + image
      final contentArray = <Map<String, dynamic>>[];

      // Add text content if present
      if (message.content.isNotEmpty) {
        if (config.useResponsesAPI) {
          contentArray.add({
            'type': 'input_text',
            'text': message.content,
          });
        } else {
          contentArray.add({
            'type': 'text',
            'text': message.content,
          });
        }
      }

      // Add image content
      if (config.useResponsesAPI) {
        contentArray.add({
          'type': 'input_image',
          'image_url': imageDataUrl,
        });
      } else {
        contentArray.add({
          'type': 'image_url',
          'image_url': {'url': imageDataUrl},
        });
      }

      result['content'] = contentArray;
      break;

    case ImageUrlMessage(url: final url):
      // Build content array with optional text + image
      final contentArray = <Map<String, dynamic>>[];

      // Add text content if present
      if (message.content.isNotEmpty) {
        if (config.useResponsesAPI) {
          contentArray.add({
            'type': 'input_text',
            'text': message.content,
          });
        } else {
          contentArray.add({
            'type': 'text',
            'text': message.content,
          });
        }
      }

      // Add image content
      if (config.useResponsesAPI) {
        contentArray.add({
          'type': 'input_image',
          'image_url': url,
        });
      } else {
        contentArray.add({
          'type': 'image_url',
          'image_url': {'url': url},
        });
      }

      result['content'] = contentArray;
      break;

    case FileMessage(data: final data):
      // Handle file messages (documents, audio, video, etc.)
      final base64Data = base64Encode(data);

      // Build content array with optional text + file
      final contentArray = <Map<String, dynamic>>[];

      // Add text content if present
      if (message.content.isNotEmpty) {
        if (config.useResponsesAPI) {
          contentArray.add({
            'type': 'input_text',
            'text': message.content,
          });
        } else {
          contentArray.add({
            'type': 'text',
            'text': message.content,
          });
        }
      }

      // Add file content
      if (config.useResponsesAPI) {
        // Responses API format: { type: 'input_file', file_data: '<base64>' }
        contentArray.add({
          'type': 'input_file',
          'file_data': base64Data,
        });
      } else {
        // Chat Completions API format: { type: 'file', file: { file_data: '<base64>' } }
        contentArray.add({
          'type': 'file',
          'file': {
            'file_data': base64Data,
          },
        });
      }

      result['content'] = contentArray;
      break;

    case ToolUseMessage(toolCalls: final toolCalls):
      result['tool_calls'] = toolCalls.map((tc) => tc.toJson()).toList();
      break;
    case ToolResultMessage(results: final results):
      // Tool results need to be converted to separate tool messages
      // This case should not happen in normal message conversion
      // as tool results are handled separately in buildRequestBody
      result['content'] =
          message.content.isNotEmpty ? message.content : 'Tool result';
      result['tool_call_id'] = results.isNotEmpty ? results.first.id : null;
      break;
  }

  return result;
}