CustomModelDefinition.fromYaml constructor
Parses one definition from yaml, strictly: name is the map key;
provider must be a catalog provider name (see providerCatalog),
baseUrl/model non-empty strings, contextWindow/maxTokens
positive integers, input a non-empty list of text/image.
Implementation
factory CustomModelDefinition.fromYaml(String name, Object? node) {
final where = 'models.custom.$name';
if (node is! YamlMap) {
throw ConfigException(
'$where must be a map with provider, baseUrl, model',
);
}
const knownFields = [
'provider',
'baseUrl',
'model',
'contextWindow',
'maxTokens',
'input',
];
for (final key in node.keys) {
if (!knownFields.contains(key)) {
throw ConfigException(
'unknown field "$key" in $where — expected '
'${knownFields.join(', ')}',
);
}
}
String required(String field) {
final value = node[field];
if (value is! String || value.trim().isEmpty) {
throw ConfigException('$where.$field must be a non-empty string');
}
return value.trim();
}
final provider = required('provider');
if (catalogProvider(provider) == null) {
throw ConfigException(
'unknown provider "$provider" in $where — supported providers: '
'${providerCatalog.keys.join(', ')}',
);
}
int? optionalInt(String field) {
final value = node[field];
if (value == null) return null;
if (value is! int || value <= 0) {
throw ConfigException('$where.$field must be a positive integer');
}
return value;
}
final input = switch (node['input']) {
null => null,
final YamlList list when list.isNotEmpty => [
for (final entry in list)
switch (entry) {
'text' || 'image' => entry as String,
_ => throw ConfigException(
'$where.input entries must be "text" or "image", got: $entry',
),
},
],
final other => throw ConfigException(
'$where.input must be a non-empty list of "text"/"image", '
'got: $other',
),
};
return CustomModelDefinition(
provider: provider,
baseUrl: required('baseUrl'),
model: required('model'),
contextWindow: optionalInt('contextWindow'),
maxTokens: optionalInt('maxTokens'),
input: input,
);
}