summaryrefslogtreecommitdiff
path: root/src/config_file.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/config_file.zig')
-rw-r--r--src/config_file.zig112
1 files changed, 112 insertions, 0 deletions
diff --git a/src/config_file.zig b/src/config_file.zig
index f7589fe..f1ae65f 100644
--- a/src/config_file.zig
+++ b/src/config_file.zig
@@ -158,11 +158,19 @@ pub const Config = struct {
default_model_ref: ?ModelRef,
tools: Policy,
extensions: Policy,
+ /// `[compaction]` settings. `compaction_keep_verbatim` is the kept-
+ /// suffix token budget (null = use libpanto's default). `compaction_model`
+ /// is an owned `<provider>:<alias>` reference string for the optional
+ /// compaction-model override; `compaction_model_ref` slices into it.
+ compaction_keep_verbatim: ?u32 = null,
+ compaction_model: ?[]const u8 = null,
+ compaction_model_ref: ?ModelRef = null,
pub fn deinit(self: *Config) void {
for (self.providers) |p| p.deinit(self.allocator);
self.allocator.free(self.providers);
if (self.default_model) |m| self.allocator.free(m);
+ if (self.compaction_model) |m| self.allocator.free(m);
self.tools.deinit(self.allocator);
self.extensions.deinit(self.allocator);
}
@@ -440,6 +448,25 @@ fn resolve(
}
}
+ // `[compaction]` settings.
+ var compaction_keep_verbatim: ?u32 = null;
+ var compaction_model: ?[]const u8 = null;
+ errdefer if (compaction_model) |m| allocator.free(m);
+ var compaction_model_ref: ?ModelRef = null;
+ if (root.get("compaction")) |compaction_tbl| {
+ if (compaction_tbl.get("keep_verbatim")) |kv| {
+ if (kv.* == .integer and kv.integer > 0) {
+ compaction_keep_verbatim = @intCast(kv.integer);
+ }
+ }
+ if (compaction_tbl.get("model")) |model_v| {
+ if (model_v.* == .string) {
+ compaction_model = try allocator.dupe(u8, model_v.string);
+ compaction_model_ref = try parseModelRef(compaction_model.?);
+ }
+ }
+ }
+
const providers_slice = try providers.toOwnedSlice(allocator);
errdefer {
for (providers_slice) |p| p.deinit(allocator);
@@ -458,6 +485,18 @@ fn resolve(
if (!found) return error.UnknownDefaultProvider;
}
+ // Validate the compaction-model override names a provider that resolved.
+ if (compaction_model_ref) |ref| {
+ var found = false;
+ for (providers_slice) |p| {
+ if (std.mem.eql(u8, p.name, ref.provider)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) return error.UnknownDefaultProvider;
+ }
+
return .{
.allocator = allocator,
.providers = providers_slice,
@@ -465,6 +504,9 @@ fn resolve(
.default_model_ref = default_model_ref,
.tools = tools,
.extensions = extensions,
+ .compaction_keep_verbatim = compaction_keep_verbatim,
+ .compaction_model = compaction_model,
+ .compaction_model_ref = compaction_model_ref,
};
}
@@ -977,3 +1019,73 @@ test "loadFromPaths: missing files are skipped" {
try testing.expectEqual(@as(usize, 0), cfg.providers.len);
try testing.expect(cfg.default_model == null);
}
+
+test "resolve: [compaction] keep_verbatim and model parse" {
+ const a = testing.allocator;
+ var env = emptyEnv(a);
+ defer env.deinit();
+ try env.put("ANTHROPIC_API_KEY", "sk-ant-xyz");
+
+ const src =
+ \\[providers.anthropic]
+ \\style = "anthropic_messages"
+ \\base_url = "https://api.anthropic.com"
+ \\api_key_env_var = "ANTHROPIC_API_KEY"
+ \\
+ \\[compaction]
+ \\keep_verbatim = 12345
+ \\model = "anthropic:haiku"
+ ;
+ const doc = try parseDoc(a, src);
+ defer doc.deinit();
+
+ var cfg = try resolve(a, &env, doc.root);
+ defer cfg.deinit();
+ try testing.expectEqual(@as(?u32, 12345), cfg.compaction_keep_verbatim);
+ try testing.expectEqualStrings("anthropic:haiku", cfg.compaction_model.?);
+ try testing.expectEqualStrings("anthropic", cfg.compaction_model_ref.?.provider);
+ try testing.expectEqualStrings("haiku", cfg.compaction_model_ref.?.model);
+}
+
+test "resolve: [compaction] absent leaves defaults null" {
+ const a = testing.allocator;
+ var env = emptyEnv(a);
+ defer env.deinit();
+ try env.put("ANTHROPIC_API_KEY", "sk-ant-xyz");
+
+ const src =
+ \\[providers.anthropic]
+ \\style = "anthropic_messages"
+ \\base_url = "https://api.anthropic.com"
+ \\api_key_env_var = "ANTHROPIC_API_KEY"
+ ;
+ const doc = try parseDoc(a, src);
+ defer doc.deinit();
+
+ var cfg = try resolve(a, &env, doc.root);
+ defer cfg.deinit();
+ try testing.expect(cfg.compaction_keep_verbatim == null);
+ try testing.expect(cfg.compaction_model == null);
+ try testing.expect(cfg.compaction_model_ref == null);
+}
+
+test "resolve: [compaction] model naming an unresolved provider errors" {
+ const a = testing.allocator;
+ var env = emptyEnv(a);
+ defer env.deinit();
+ try env.put("ANTHROPIC_API_KEY", "sk-ant-xyz");
+
+ const src =
+ \\[providers.anthropic]
+ \\style = "anthropic_messages"
+ \\base_url = "https://api.anthropic.com"
+ \\api_key_env_var = "ANTHROPIC_API_KEY"
+ \\
+ \\[compaction]
+ \\model = "openai:gpt-4o"
+ ;
+ const doc = try parseDoc(a, src);
+ defer doc.deinit();
+
+ try testing.expectError(error.UnknownDefaultProvider, resolve(a, &env, doc.root));
+}