write static method
void
write({})
Writes the given fields into ai.yaml, updating only the keys provided and
preserving the rest (and surrounding comments). Creates the file and its
parent directory (mode 600/700 on POSIX) when missing.
A null value leaves the key untouched. An empty-string value clears
the key — it is removed from the file so resolution falls back to the
default (e.g. clearing model reverts to the per-provider default;
clearing executorModel reverts to model).
Implementation
static void write({
AiProviderKind? provider,
String? model,
String? apiKey,
String? plannerModel,
String? executorModel,
String? explainerModel,
AgentMode? mode,
String? language,
String? baseUrl,
int? maxSteps,
String? path,
String? home,
}) {
// Partition the requested changes: non-empty values are written, while
// empty strings mean "clear" — the key is removed so resolution uses the
// default. `null` values are skipped entirely (untouched).
final fields = <String, Object?>{
'provider': provider?.wireName,
'model': model,
'apiKey': apiKey,
'plannerModel': plannerModel,
'executorModel': executorModel,
'explainerModel': explainerModel,
'mode': mode?.wireName,
'language': language,
'baseUrl': baseUrl,
'maxSteps': maxSteps,
};
final updates = <String, Object>{};
final removals = <String>[];
for (final e in fields.entries) {
final v = e.value;
if (v == null) continue;
if (v is String && v.isEmpty) {
removals.add(e.key);
} else {
updates[e.key] = v;
}
}
if (updates.isEmpty && removals.isEmpty) return;
final file = File(path ?? defaultPath(home: home));
final existing = file.existsSync() ? file.readAsStringSync() : '';
if (existing.trim().isEmpty) {
// Nothing to remove from a fresh file; only the set values are written.
if (updates.isEmpty) return;
file.parent.createSync(recursive: true);
_restrictDir(file.parent);
file.writeAsStringSync(_template(updates));
_restrictFile(file);
return;
}
final doc = loadYaml(existing);
if (doc is Map && doc['ai'] is Map) {
final aiMap = doc['ai'] as Map;
final editor = YamlEditor(existing);
for (final e in updates.entries) {
editor.update(['ai', e.key], e.value);
}
for (final key in removals) {
if (aiMap.containsKey(key)) editor.remove(['ai', key]);
}
file.writeAsStringSync(editor.toString());
} else if (doc is Map) {
if (updates.isEmpty) return; // no `ai` map yet, nothing to remove
final editor = YamlEditor(existing)..update(['ai'], updates);
file.writeAsStringSync(editor.toString());
} else {
// Root is not a mapping (unexpected); replace with a fresh template.
if (updates.isEmpty) return;
file.writeAsStringSync(_template(updates));
}
_restrictFile(file);
}