1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
const std = @import("std");
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
// Parse -p flag
const args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
var prompt: ?[]const u8 = null;
var i: usize = 1;
while (i < args.len) : (i += 1) {
if (std.mem.eql(u8, args[i], "-p") and i + 1 < args.len) {
i += 1;
prompt = args[i];
}
}
const prompt_str = prompt orelse @panic("Prompt must not be empty");
const api_key = std.posix.getenv("OPENROUTER_API_KEY") orelse @panic("OPENROUTER_API_KEY is not set");
const base_url = std.posix.getenv("OPENROUTER_BASE_URL") orelse "https://openrouter.ai/api/v1";
// Build request body
var body_out: std.io.Writer.Allocating = .init(allocator);
defer body_out.deinit();
var jw: std.json.Stringify = .{ .writer = &body_out.writer };
try jw.write(.{
.model = "anthropic/claude-haiku-4.5",
.messages = &[_]struct { role: []const u8, content: []const u8 }{
.{ .role = "user", .content = prompt_str },
},
.tools = &[_]struct {
type: []const u8,
function: struct {
name: []const u8,
description: []const u8,
parameters: struct {
type: []const u8,
properties: struct {
file_path: struct {
type: []const u8,
description: []const u8,
},
},
required: []const []const u8,
},
},
}{
.{
.type = "function",
.function = .{
.name = "Read",
.description = "Read and return the contents of a file",
.parameters = .{
.type = "object",
.properties = .{
.file_path = .{
.type = "string",
.description = "The path to the file to read",
},
},
.required = &[_][]const u8{"file_path"},
},
},
},
},
});
const body = body_out.written();
// Build URL and auth header
const url_str = try std.fmt.allocPrint(allocator, "{s}/chat/completions", .{base_url});
defer allocator.free(url_str);
const auth_value = try std.fmt.allocPrint(allocator, "Bearer {s}", .{api_key});
defer allocator.free(auth_value);
// Make HTTP request
var client: std.http.Client = .{ .allocator = allocator };
defer client.deinit();
var response_out: std.io.Writer.Allocating = .init(allocator);
defer response_out.deinit();
_ = try client.fetch(.{
.location = .{ .url = url_str },
.method = .POST,
.payload = body,
.extra_headers = &.{
.{ .name = "content-type", .value = "application/json" },
.{ .name = "authorization", .value = auth_value },
},
.response_writer = &response_out.writer,
});
const response_body = response_out.written();
// Parse response
const parsed = try std.json.parseFromSlice(std.json.Value, allocator, response_body, .{});
defer parsed.deinit();
const choices = parsed.value.object.get("choices") orelse @panic("No choices in response");
if (choices.array.items.len == 0) {
@panic("No choices in response");
}
std.debug.print("Logs from your program will appear here!\n", .{});
const message = choices.array.items[0].object.get("message").?;
// Check for tool_calls in the response
if (message.object.get("tool_calls")) |tool_calls_val| {
if (tool_calls_val != .null and tool_calls_val.array.items.len > 0) {
const tool_call = tool_calls_val.array.items[0];
const func = tool_call.object.get("function").?;
const func_name = func.object.get("name").?.string;
const arguments_str = func.object.get("arguments").?.string;
if (std.mem.eql(u8, func_name, "Read")) {
const args_parsed = try std.json.parseFromSlice(std.json.Value, allocator, arguments_str, .{});
defer args_parsed.deinit();
const file_path = args_parsed.value.object.get("file_path").?.string;
std.debug.print("Reading file: {s}\n", .{file_path});
const file_contents = try std.fs.cwd().readFileAlloc(allocator, file_path, std.math.maxInt(usize));
defer allocator.free(file_contents);
try std.fs.File.stdout().writeAll(file_contents);
return;
}
}
}
// No tool call — print the text content directly
const content = message.object.get("content").?.string;
try std.fs.File.stdout().writeAll(content);
}
|