sendChatRequest method

  1. @override
Future<Map<String, dynamic>> sendChatRequest(
  1. List<Map<String, dynamic>> messages,
  2. List<Map<String, dynamic>>? tools, {
  3. double? temperature,
  4. int? maxCompletionTokens,
  5. double? topP,
  6. bool? stream,
  7. String? reasoningEffort,
  8. dynamic stop,
  9. CancellationToken? cancellationToken,
})
override

Sends a single, complete chat request to the LLM.

Implementation

@override
Future<Map<String, dynamic>> sendChatRequest(
  List<Map<String, dynamic>> messages,
  List<Map<String, dynamic>>? tools, {
  double? temperature,
  int? maxCompletionTokens,
  double? topP,
  bool? stream,
  String? reasoningEffort,
  dynamic stop,
  CancellationToken? cancellationToken,
}) async {
  sdkLogger.info(
    'Sending chat request to OpenRouter (model: $model)',
    tag: 'OPENROUTER',
    extra: {
      'model': model,
      'message_count': messages.length,
      'has_tools': tools != null && tools.isNotEmpty,
    },
  );

  final bodyMap = {
    'model': model,
    'messages': messages,
    'tools': tools,
    'tool_choice': 'auto',
    if ((temperature ?? this.temperature) != null)
      'temperature': temperature ?? this.temperature,
    if ((maxCompletionTokens ?? this.maxCompletionTokens) != null)
      'max_tokens': maxCompletionTokens ?? this.maxCompletionTokens,
    if ((topP ?? this.topP) != null) 'top_p': topP ?? this.topP,
    if ((stream) != null) 'stream': stream,
    if ((reasoningEffort ?? this.reasoningEffort) != null)
      'reasoning_effort': reasoningEffort ?? this.reasoningEffort,
    if ((stop ?? this.stop) != null) 'stop': stop ?? this.stop,
  };

  final body = jsonEncode(bodyMap);
  const int maxRetries = 3;
  const Duration baseDelay = Duration(seconds: 1);

  for (int attempt = 1; attempt <= maxRetries; attempt++) {
    if (cancellationToken?.isCancelled == true) {
      throw VanturaCancellationException();
    }

    try {
      final response = await _httpClient.post(
        Uri.parse(_baseUrl),
        headers: _getHeaders(),
        body: body,
      );

      if (response.statusCode == 200) {
        return jsonDecode(response.body);
      } else if (response.statusCode == 429) {
        if (attempt == maxRetries) {
          throw VanturaRateLimitException(
            'Rate limit exceeded',
            responseBody: response.body,
          );
        }
        final delay = baseDelay * attempt;
        onRetry?.call(attempt, delay, 'Rate limited (429)');
        await Future.delayed(delay);
        continue;
      } else {
        throw VanturaApiException(
          'OpenRouter request failed',
          statusCode: response.statusCode,
          responseBody: response.body,
        );
      }
    } on http.ClientException catch (e) {
      if (attempt == maxRetries) rethrow;
      final delay = baseDelay * attempt;
      onRetry?.call(attempt, delay, e);
      await Future.delayed(delay);
    }
  }
  throw Exception('Unexpected error in OpenRouter request');
}