listModels method

  1. @override
Future<List<AiModel>> listModels()
override

Fetch available models from the provider's API.

Implementation

@override
Future<List<AiModel>> listModels() async {
  final apiKey = await _getApiKey();
  if (apiKey == null || apiKey.isEmpty) {
    return _provider.availableModels
        .map((m) => AiModel(id: m.id, name: m.name))
        .toList();
  }

  // Web: api.anthropic.com blocks browser requests at the CORS preflight.
  // Route through the ai-proxy Edge Function instead.
  if (kIsWeb) {
    final models = await listModelsViaProxy(
      dio: _dio,
      provider: 'claude',
      credential: apiKey,
    );
    if (models.isNotEmpty) return models;
    return _provider.availableModels
        .map((m) => AiModel(id: m.id, name: m.name))
        .toList();
  }

  try {
    final response = await _dio.get(
      'https://api.anthropic.com/v1/models',
      options: Options(
        headers: {
          'x-api-key': apiKey,
          'anthropic-version': AiProviderConfig.claudeApiVersion,
        },
      ),
    );

    final data = response.data as Map<String, dynamic>;
    final models = data['data'] as List<dynamic>;
    final result = <AiModel>[];
    for (final model in models) {
      final m = model as Map<String, dynamic>;
      final id = m['id'] as String;
      final name = m['display_name'] as String? ?? id;
      result.add(AiModel(id: id, name: name));
    }
    // Sort by name for consistent display.
    result.sort((a, b) => a.name.compareTo(b.name));
    return result;
  } catch (e) {
    dev.log('Failed to list Claude models: $e', name: 'ClaudeDatasource');
    // Fall back to static list.
    return _provider.availableModels
        .map((m) => AiModel(id: m.id, name: m.name))
        .toList();
  }
}