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.zig69
1 files changed, 68 insertions, 1 deletions
diff --git a/src/config_file.zig b/src/config_file.zig
index 1823177..8f6725c 100644
--- a/src/config_file.zig
+++ b/src/config_file.zig
@@ -77,6 +77,10 @@ pub const Provider = struct {
/// the name used on the left of a `<provider>:<model>` reference.
name: []const u8,
style: APIStyle,
+ /// User-facing sub-dialect for styles that share a protocol family.
+ /// Currently only `style = "openai_responses"` supports `dialect = "codex"`,
+ /// which maps to internal `APIStyle.openai_codex_responses`.
+ dialect: ?[]const u8 = null,
base_url: []const u8,
/// The `auth.<name>` session this provider draws its credential from.
auth_name: []const u8,
@@ -90,6 +94,7 @@ pub const Provider = struct {
pub fn deinit(self: Provider, alloc: Allocator) void {
alloc.free(self.name);
+ if (self.dialect) |d| alloc.free(d);
alloc.free(self.base_url);
alloc.free(self.auth_name);
// `extra_headers` lives in the Config auth arena; not freed here.
@@ -213,6 +218,14 @@ pub fn buildProviderConfig(
.max_tokens = max_tokens,
.extra_headers = prov.extra_headers,
} },
+ .openai_codex_responses => return .{ .openai_codex_responses = .{
+ .api_key = api_key,
+ .base_url = prov.base_url,
+ .model = wire_model,
+ .reasoning = reasoning,
+ .max_tokens = max_tokens,
+ .extra_headers = prov.extra_headers,
+ } },
}
}
@@ -677,7 +690,16 @@ fn resolveProvider(
const style_str = (val.get("style") orelse return error.InvalidProvider).asString() orelse
return error.InvalidProvider;
- const style = std.meta.stringToEnum(APIStyle, style_str) orelse return error.InvalidProvider;
+ var style = std.meta.stringToEnum(APIStyle, style_str) orelse return error.InvalidProvider;
+ if (style == .openai_codex_responses) return error.InvalidProvider;
+ const dialect = if (tomlStr(val, "dialect")) |d| d else null;
+ if (dialect) |d| {
+ if (std.mem.eql(u8, style_str, "openai_responses") and std.mem.eql(u8, d, "codex")) {
+ style = .openai_codex_responses;
+ } else {
+ return error.InvalidProvider;
+ }
+ }
const base_url = (val.get("base_url") orelse return error.InvalidProvider).asString() orelse
return error.InvalidProvider;
@@ -699,6 +721,7 @@ fn resolveProvider(
return .{
.name = try allocator.dupe(u8, name),
.style = style,
+ .dialect = if (dialect) |d| try allocator.dupe(u8, d) else null,
.base_url = try allocator.dupe(u8, base_url),
.auth_name = try allocator.dupe(u8, auth_name),
.prompt_cache = prompt_cache,
@@ -1231,6 +1254,50 @@ test "resolve: provider extra_headers flow into the built provider config" {
try testing.expectEqualStrings("tok", pc.openai_chat.api_key);
}
+test "resolve: openai_responses codex dialect maps to internal API style" {
+ const a = testing.allocator;
+ var env = emptyEnv(a);
+ defer env.deinit();
+ const src =
+ \\[providers.codex]
+ \\style = "openai_responses"
+ \\dialect = "codex"
+ \\base_url = "https://chatgpt.com/backend-api"
+ \\auth = "k"
+ \\
+ \\[auth.k]
+ \\key = "tok"
+ ;
+ const doc = try parseDoc(a, src);
+ defer doc.deinit();
+ var cfg = try resolve(a, &env, doc.root);
+ defer cfg.deinit();
+
+ try testing.expectEqual(APIStyle.openai_codex_responses, cfg.provider("codex").?.style);
+ var defs = models_toml.ModelRegistry.init(a);
+ defer defs.deinit();
+ const pc = try buildProviderConfig(&cfg, &defs, .{ .provider = "codex", .model = "gpt-5.5" });
+ try testing.expectEqual(APIStyle.openai_codex_responses, pc.style());
+}
+
+test "resolve: internal openai_codex_responses style is not user-facing" {
+ const a = testing.allocator;
+ var env = emptyEnv(a);
+ defer env.deinit();
+ const src =
+ \\[providers.codex]
+ \\style = "openai_codex_responses"
+ \\base_url = "https://chatgpt.com/backend-api"
+ \\auth = "k"
+ \\
+ \\[auth.k]
+ \\key = "tok"
+ ;
+ const doc = try parseDoc(a, src);
+ defer doc.deinit();
+ try testing.expectError(error.InvalidProvider, resolve(a, &env, doc.root));
+}
+
test "resolve: prompt_cache defaults true and is parsed when set" {
const a = testing.allocator;
var env = emptyEnv(a);