CustomProviderEntry.fromYaml constructor

CustomProviderEntry.fromYaml(
  1. Object? node
)

Parses one yaml map from the customProviders: list. Throws ConfigException on bad shapes (bad config must surface, never silently vanish).

Implementation

factory CustomProviderEntry.fromYaml(Object? node) {
  if (node is! Map) {
    throw ConfigException('customProviders entries must be maps, got: $node');
  }
  String requireString(String field) {
    final value = node[field];
    if (value is! String || value.isEmpty) {
      throw ConfigException(
        'customProviders entry needs a non-empty "$field"',
      );
    }
    return value;
  }

  final apiType = requireString('apiType');
  if (!customProviderApiTypes.contains(apiType)) {
    throw ConfigException(
      'customProviders entry "$apiType" is not a supported apiType '
      '(${customProviderApiTypes.join(', ')})',
    );
  }
  final keyName = node['keyName'];
  final authMethod = _parseAuthMethod(node['authMethod']);
  final name = requireString('name');
  final authHeader = parseAuthHeaderName(
    node['authHeader'],
    'customProviders entry "$name"',
  );
  validateAuthHeaderDialect(
    authHeader,
    catalogProvider(apiType),
    'customProviders entry "$name"',
  );
  return CustomProviderEntry(
    name: name,
    apiType: apiType,
    baseUrl: requireString('baseUrl'),
    modelId: requireString('modelId'),
    keyName: keyName is String && keyName.isNotEmpty ? keyName : null,
    authMethod: authMethod,
    // Named error (issue #964 AC5): the entry owns the bad value, so the
    // message names the entry.
    authHeader: authHeader,
    // Per-provider stall-recovery tuning (issue #1398): the watchdog
    // knobs ride the registry entry, same place baseUrl/keys live.
    connectTimeout: parseProviderTimeoutMs(
      node['connectTimeoutMs'],
      'connectTimeoutMs',
      'customProviders entry "$name"',
    ),
    streamIdleTimeout: parseProviderTimeoutMs(
      node['streamIdleTimeoutMs'],
      'streamIdleTimeoutMs',
      'customProviders entry "$name"',
    ),
    // gh-1679: an entry recorded while its key write degraded to
    // session-only keeps the marker so the next boot can surface the
    // degradation while the slot stays empty.
    keyNotPersisted: node['keyNotPersisted'] == true,
    // Issue #1809: the CodeMie project picked at connect time (null for
    // non-CodeMie entries and entries connected before the field existed).
    project:
        node['project'] is String && (node['project'] as String).isNotEmpty
        ? node['project'] as String
        : null,
  );
}