summaryrefslogtreecommitdiff
path: root/src/main.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.zig')
-rw-r--r--src/main.zig116
1 files changed, 82 insertions, 34 deletions
diff --git a/src/main.zig b/src/main.zig
index 832f037..688b61d 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -85,39 +85,82 @@ const CLIReceiver = struct {
}
};
+fn loadConfig(environ_map: *const std.process.Environ.Map) !panto.config.Config {
+ const style_str = environ_map.get("PANTO_API_STYLE") orelse "openai_chat";
+ const style = std.meta.stringToEnum(panto.config.APIStyle, style_str) orelse {
+ std.debug.print(
+ "error: PANTO_API_STYLE must be one of: openai_chat, anthropic_messages (got: {s})\n",
+ .{style_str},
+ );
+ return error.InvalidApiStyle;
+ };
+
+ switch (style) {
+ .openai_chat => {
+ const api_key = environ_map.get("OPENAI_API_KEY") orelse {
+ std.debug.print("error: OPENAI_API_KEY is required\n", .{});
+ return error.MissingApiKey;
+ };
+ const base_url = environ_map.get("OPENAI_BASE_URL") orelse "https://api.openai.com/v1";
+ const model = environ_map.get("OPENAI_MODEL") orelse {
+ std.debug.print("error: OPENAI_MODEL is required\n", .{});
+ return error.MissingModel;
+ };
+ const reasoning: panto.config.ReasoningEffort =
+ if (environ_map.get("OPENAI_REASONING")) |val|
+ std.meta.stringToEnum(panto.config.ReasoningEffort, val) orelse {
+ std.debug.print(
+ "error: OPENAI_REASONING must be one of: default, off, minimal, low, medium, high (got: {s})\n",
+ .{val},
+ );
+ return error.InvalidReasoning;
+ }
+ else
+ .default;
+ return .{ .openai_chat = .{
+ .api_key = api_key,
+ .base_url = base_url,
+ .model = model,
+ .reasoning = reasoning,
+ } };
+ },
+ .anthropic_messages => {
+ const api_key = environ_map.get("ANTHROPIC_API_KEY") orelse {
+ std.debug.print("error: ANTHROPIC_API_KEY is required\n", .{});
+ return error.MissingApiKey;
+ };
+ const base_url = environ_map.get("ANTHROPIC_BASE_URL") orelse "https://api.anthropic.com";
+ const model = environ_map.get("ANTHROPIC_MODEL") orelse {
+ std.debug.print("error: ANTHROPIC_MODEL is required\n", .{});
+ return error.MissingModel;
+ };
+ const api_version = environ_map.get("ANTHROPIC_API_VERSION") orelse "2023-06-01";
+ const max_tokens: u32 = if (environ_map.get("ANTHROPIC_MAX_TOKENS")) |val|
+ std.fmt.parseInt(u32, val, 10) catch {
+ std.debug.print(
+ "error: ANTHROPIC_MAX_TOKENS must be a positive integer (got: {s})\n",
+ .{val},
+ );
+ return error.InvalidMaxTokens;
+ }
+ else
+ 4096;
+ return .{ .anthropic_messages = .{
+ .api_key = api_key,
+ .base_url = base_url,
+ .model = model,
+ .api_version = api_version,
+ .max_tokens = max_tokens,
+ } };
+ },
+ }
+}
+
pub fn main(init: std.process.Init) !void {
const alloc = init.gpa;
const io = init.io;
- const api_key = init.environ_map.get("PANTO_API_KEY") orelse {
- std.debug.print("error: PANTO_API_KEY is required\n", .{});
- return error.MissingApiKey;
- };
- const base_url = init.environ_map.get("PANTO_BASE_URL") orelse "https://api.openai.com/v1";
- const model = init.environ_map.get("PANTO_MODEL") orelse {
- std.debug.print("error: PANTO_MODEL is required\n", .{});
- return error.MissingModel;
- };
-
- const reasoning: panto.config.ReasoningEffort =
- if (init.environ_map.get("PANTO_REASONING")) |val|
- std.meta.stringToEnum(panto.config.ReasoningEffort, val) orelse {
- std.debug.print(
- "error: PANTO_REASONING must be one of: default, off, minimal, low, medium, high (got: {s})\n",
- .{val},
- );
- return error.InvalidReasoning;
- }
- else
- .default;
-
- const config = panto.config.Config{
- .api_style = .openai_chat,
- .api_key = api_key,
- .base_url = base_url,
- .model = model,
- .reasoning = reasoning,
- };
+ const config = try loadConfig(init.environ_map);
var stdout_buffer: [4096]u8 = undefined;
var stdout_file = std.Io.File.stdout().writer(io, &stdout_buffer);
@@ -131,12 +174,17 @@ pub fn main(init: std.process.Init) !void {
defer conv.deinit();
try conv.addSystemMessage("You are a helpful assistant.");
- var provider_impl = panto.provider_openai_chat.OpenAIChatProvider.init(alloc, io, config);
- defer provider_impl.deinit();
+ const prov = try panto.provider.Provider.init(alloc, io, config);
+ const agent = panto.agent.Agent.init(alloc, prov);
+ defer agent.deinit();
- const agent = panto.agent.Agent.init(alloc, provider_impl.provider());
-
- try stdout.print("panto — model: {s} @ {s}\n", .{ config.model, config.base_url });
+ const banner_model: []const u8 = switch (config) {
+ inline else => |c| c.model,
+ };
+ const banner_base: []const u8 = switch (config) {
+ inline else => |c| c.base_url,
+ };
+ try stdout.print("panto — {s}: {s} @ {s}\n", .{ @tagName(config), banner_model, banner_base });
try stdout.print("> ", .{});
try stdout_file.flush();