ModelRef.fromYaml constructor

ModelRef.fromYaml(
  1. Object? node, {
  2. String? role,
})

Parses one chain entry from yaml: either the string shorthand or a map with provider/model plus optional overrides.

Implementation

factory ModelRef.fromYaml(Object? node, {String? role}) {
  switch (node) {
    case String value:
      return ModelRef.parse(value, role: role);
    case YamlMap entry:
      // Leaf reads bind to `entry` (not `map`/`doc`): the settings
      // completeness gate counts literal `map['…']` reads in parser
      // sources as TOP-LEVEL keys, and these are section leaves
      // (issue #964 review — `authHeader` tripped the ratchet).
      final provider = entry['provider'];
      final model = entry['model'];
      if (provider is! String || provider.trim().isEmpty) {
        throw ConfigException(
          'model chain entry${role == null ? '' : ' in role "$role"'} '
          'is missing a "provider" string',
        );
      }
      if (model is! String || model.trim().isEmpty) {
        throw ConfigException(
          'model chain entry${role == null ? '' : ' in role "$role"'} '
          'is missing a "model" string',
        );
      }
      final where =
          'model chain entry${role == null ? '' : ' in role "$role"'}';
      final authHeader = parseAuthHeaderName(entry['authHeader'], where);
      validateAuthHeaderDialect(authHeader, catalogProvider(provider), where);
      return ModelRef(
        provider: provider.trim(),
        modelId: model.trim(),
        apiKeyName: _optionalString(entry, 'apiKeyName', role),
        baseUrl: _optionalString(entry, 'baseUrl', role),
        contextWindow: _optionalInt(entry, 'contextWindow', role),
        maxTokens: _optionalInt(entry, 'maxTokens', role),
        input: _optionalInput(entry, role),
        thinkingLevel: _optionalThinkingLevel(entry, role),
        authHeader: authHeader,
        // Per-provider stall-recovery tuning (issue #1398): the watchdog
        // knobs ride the chain entry, same place baseUrl/keys live.
        connectTimeout: parseProviderTimeoutMs(
          entry['connectTimeoutMs'],
          'connectTimeoutMs',
          where,
        ),
        streamIdleTimeout: parseProviderTimeoutMs(
          entry['streamIdleTimeoutMs'],
          'streamIdleTimeoutMs',
          where,
        ),
      );
    default:
      throw ConfigException(
        'invalid model chain entry${role == null ? '' : ' in role "$role"'}: '
        'expected "provider/modelId" or a map, got ${node.runtimeType}',
      );
  }
}