ModelRef.fromYaml constructor
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}',
);
}
}