mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-06-11 09:35:59 -04:00
agent: reduce allocations and reuse buffers
This commit is contained in:
@@ -443,18 +443,17 @@ fn runScript(self: *Self, path: []const u8) bool {
|
||||
};
|
||||
defer file.close();
|
||||
|
||||
const content = file.readToEndAlloc(self.allocator, 10 * 1024 * 1024) catch |err| {
|
||||
self.terminal.printErrorFmt("Failed to read script: {s}", .{@errorName(err)});
|
||||
return false;
|
||||
};
|
||||
defer self.allocator.free(content);
|
||||
|
||||
self.terminal.printInfoFmt("Running script: {s}", .{path});
|
||||
|
||||
var script_arena: std.heap.ArenaAllocator = .init(self.allocator);
|
||||
defer script_arena.deinit();
|
||||
const sa = script_arena.allocator();
|
||||
|
||||
const content = file.readToEndAlloc(sa, 10 * 1024 * 1024) catch |err| {
|
||||
self.terminal.printErrorFmt("Failed to read script: {s}", .{@errorName(err)});
|
||||
return false;
|
||||
};
|
||||
|
||||
var iter: Command.ScriptIterator = .init(sa, content);
|
||||
var last_comment: ?[]const u8 = null;
|
||||
var replacements: std.ArrayList(Replacement) = .empty;
|
||||
@@ -1021,8 +1020,8 @@ fn buildUserMessageParts(
|
||||
}
|
||||
|
||||
var parts: std.ArrayList(zenai.provider.ContentPart) = .empty;
|
||||
const combined = try std.fmt.allocPrint(ma, "{s}{s}", .{ text_prefix.items, user_input });
|
||||
try parts.append(ma, .{ .text = combined });
|
||||
try text_prefix.appendSlice(ma, user_input);
|
||||
try parts.append(ma, .{ .text = try text_prefix.toOwnedSlice(ma) });
|
||||
for (inline_parts.items) |p| try parts.append(ma, p);
|
||||
return parts.toOwnedSlice(ma);
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ const Self = @This();
|
||||
allocator: std.mem.Allocator,
|
||||
file: ?std.fs.File,
|
||||
needs_separator: bool,
|
||||
/// Reused between `record()` calls so each command line doesn't alloc/free.
|
||||
/// Cleared with `clearRetainingCapacity` instead.
|
||||
buf: std.Io.Writer.Allocating,
|
||||
|
||||
/// Append-open `path`, inserting a leading newline if the file is non-empty.
|
||||
/// A null path disables recording.
|
||||
@@ -27,10 +30,11 @@ pub fn init(allocator: std.mem.Allocator, path: ?[]const u8) Self {
|
||||
break :blk f;
|
||||
} else null;
|
||||
|
||||
return .{ .allocator = allocator, .file = file, .needs_separator = false };
|
||||
return .{ .allocator = allocator, .file = file, .needs_separator = false, .buf = .init(allocator) };
|
||||
}
|
||||
|
||||
pub fn deinit(self: *Self) void {
|
||||
self.buf.deinit();
|
||||
if (self.file) |f| f.close();
|
||||
}
|
||||
|
||||
@@ -38,11 +42,10 @@ pub fn record(self: *Self, cmd: Command.Command) void {
|
||||
const f = self.file orelse return;
|
||||
if (!cmd.isRecorded()) return;
|
||||
|
||||
var aw: std.Io.Writer.Allocating = .init(self.allocator);
|
||||
defer aw.deinit();
|
||||
cmd.format(&aw.writer) catch return;
|
||||
aw.writer.writeByte('\n') catch return;
|
||||
_ = f.write(aw.written()) catch return;
|
||||
self.buf.clearRetainingCapacity();
|
||||
cmd.format(&self.buf.writer) catch return;
|
||||
self.buf.writer.writeByte('\n') catch return;
|
||||
_ = f.write(self.buf.written()) catch return;
|
||||
self.needs_separator = true;
|
||||
}
|
||||
|
||||
@@ -61,7 +64,7 @@ test "record writes state-mutating commands" {
|
||||
|
||||
const file = tmp.dir.createFile("test.lp", .{ .read = true }) catch unreachable;
|
||||
|
||||
var recorder: Self = .{ .allocator = std.testing.allocator, .file = file, .needs_separator = false };
|
||||
var recorder: Self = .{ .allocator = std.testing.allocator, .file = file, .needs_separator = false, .buf = .init(std.testing.allocator) };
|
||||
defer recorder.deinit();
|
||||
|
||||
recorder.record(Command.parse("GOTO https://example.com"));
|
||||
@@ -103,7 +106,7 @@ test "record skips empty and comment lines" {
|
||||
|
||||
const file = tmp.dir.createFile("test2.lp", .{ .read = true }) catch unreachable;
|
||||
|
||||
var recorder: Self = .{ .allocator = std.testing.allocator, .file = file, .needs_separator = false };
|
||||
var recorder: Self = .{ .allocator = std.testing.allocator, .file = file, .needs_separator = false, .buf = .init(std.testing.allocator) };
|
||||
defer recorder.deinit();
|
||||
|
||||
recorder.record(Command.parse(""));
|
||||
@@ -120,7 +123,7 @@ test "record skips empty and comment lines" {
|
||||
}
|
||||
|
||||
test "recorder with null file is no-op" {
|
||||
var recorder: Self = .{ .allocator = std.testing.allocator, .file = null, .needs_separator = false };
|
||||
var recorder: Self = .{ .allocator = std.testing.allocator, .file = null, .needs_separator = false, .buf = .init(std.testing.allocator) };
|
||||
recorder.record(Command.parse("GOTO https://example.com"));
|
||||
recorder.recordComment("# test");
|
||||
recorder.deinit();
|
||||
|
||||
@@ -1011,9 +1011,11 @@ pub fn substituteEnvVars(arena: std.mem.Allocator, input: []const u8) []const u8
|
||||
// Same gate as `execGetEnv`: only `LP_*` is resolvable. A
|
||||
// prompt-injected `fill('$ANTHROPIC_API_KEY')` would otherwise
|
||||
// leak the resolved value into the page DOM.
|
||||
const env_val: ?[:0]const u8 = if (std.ascii.startsWithIgnoreCase(name, "LP_")) blk: {
|
||||
const name_z = arena.dupeZ(u8, name) catch return input;
|
||||
break :blk std.posix.getenv(name_z);
|
||||
var name_buf: [256]u8 = undefined;
|
||||
const env_val: ?[:0]const u8 = if (std.ascii.startsWithIgnoreCase(name, "LP_") and name.len < name_buf.len) blk: {
|
||||
@memcpy(name_buf[0..name.len], name);
|
||||
name_buf[name.len] = 0;
|
||||
break :blk std.posix.getenv(name_buf[0..name.len :0]);
|
||||
} else null;
|
||||
if (env_val) |val| {
|
||||
result.appendSlice(arena, val) catch return input;
|
||||
|
||||
Reference in New Issue
Block a user