From ec8d53d68477051f1e387efe01bbcc2e210060d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= Date: Thu, 30 Apr 2026 16:06:05 +0200 Subject: [PATCH] agent: rename exit to quit and remove command aliases --- src/agent/Agent.zig | 12 ++++++------ src/agent/Command.zig | 32 ++++++++++++++++---------------- src/agent/CommandExecutor.zig | 2 +- src/agent/Terminal.zig | 3 +-- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/agent/Agent.zig b/src/agent/Agent.zig index 9994fd12..39ae67ee 100644 --- a/src/agent/Agent.zig +++ b/src/agent/Agent.zig @@ -291,7 +291,7 @@ fn runRepl(self: *Self) void { } switch (cmd) { - .exit => break :repl, + .quit => break :repl, .comment => continue :repl, .login => self.processUserMessage(login_prompt, line) catch |err| { self.terminal.printErrorFmt("LOGIN failed: {s}", .{@errorName(err)}); @@ -313,7 +313,7 @@ fn runRepl(self: *Self) void { } /// Handle a REPL line that started with `/`. Returns `true` if the user asked -/// to exit (`/quit` or `/exit`), `false` otherwise. All errors are printed and +/// to quit (`/quit`), `false` otherwise. All errors are printed and /// swallowed — the REPL must not die from a malformed slash command. fn handleSlash(self: *Self, body: []const u8) bool { const split = SlashCommand.splitNameRest(body) orelse { @@ -323,7 +323,7 @@ fn handleSlash(self: *Self, body: []const u8) bool { const name = split.name; const rest = split.rest; - if (std.mem.eql(u8, name, "quit") or std.mem.eql(u8, name, "exit")) { + if (std.mem.eql(u8, name, "quit")) { return true; } if (std.mem.eql(u8, name, "help")) { @@ -376,7 +376,7 @@ fn printSlashHelp(self: *Self, target: []const u8) void { const summary = firstSentence(s.description); self.terminal.printInfoFmt(" /{s} — {s}", .{ s.tool_name, summary }); } - self.terminal.printInfo("Meta: /help , /quit, /exit"); + self.terminal.printInfo("Meta: /help , /quit"); return; } const lookup = if (target[0] == '/') target[1..] else target; @@ -452,8 +452,8 @@ fn runScript(self: *Self, path: []const u8) bool { while (iter.next()) |entry| { switch (entry.command) { - .exit => { - self.terminal.printInfo("EXIT — stopping script."); + .quit => { + self.terminal.printInfo("QUIT — stopping script."); break; }, .comment => { diff --git a/src/agent/Command.zig b/src/agent/Command.zig index 73eede82..e99cf6e7 100644 --- a/src/agent/Command.zig +++ b/src/agent/Command.zig @@ -36,13 +36,13 @@ pub const Command = union(enum) { eval_js: []const u8, login: void, accept_cookies: void, - exit: void, + quit: void, comment: void, natural_language: []const u8, pub fn isRecorded(self: Command) bool { return switch (self) { - .tree, .markdown, .comment, .exit => false, + .tree, .markdown, .comment, .quit => false, .goto, .click, .type_cmd, .wait, .scroll, .hover, .select, .check, .extract, .eval_js, .login, .accept_cookies => true, .natural_language => |text| text.len > 0, }; @@ -100,7 +100,7 @@ pub const Command = union(enum) { try writer.print("EVAL {f}", .{quote(script)}), .login => try writer.writeAll("LOGIN"), .accept_cookies => try writer.writeAll("ACCEPT_COOKIES"), - .exit => try writer.writeAll("EXIT"), + .quit => try writer.writeAll("QUIT"), .comment => try writer.writeAll("#"), .natural_language => |text| try writer.writeAll(text), } @@ -193,7 +193,7 @@ pub fn parse(line: []const u8) Command { return .{ .tree = {} }; } - if (std.ascii.eqlIgnoreCase(cmd_word, "MARKDOWN") or std.ascii.eqlIgnoreCase(cmd_word, "MD")) { + if (std.ascii.eqlIgnoreCase(cmd_word, "MARKDOWN")) { return .{ .markdown = {} }; } @@ -211,12 +211,12 @@ pub fn parse(line: []const u8) Command { return .{ .login = {} }; } - if (std.ascii.eqlIgnoreCase(cmd_word, "ACCEPT_COOKIES") or std.ascii.eqlIgnoreCase(cmd_word, "ACCEPT-COOKIES")) { + if (std.ascii.eqlIgnoreCase(cmd_word, "ACCEPT_COOKIES")) { return .{ .accept_cookies = {} }; } - if (std.ascii.eqlIgnoreCase(cmd_word, "EXIT") or std.ascii.eqlIgnoreCase(cmd_word, "QUIT")) { - return .{ .exit = {} }; + if (std.ascii.eqlIgnoreCase(cmd_word, "QUIT")) { + return .{ .quit = {} }; } return .{ .natural_language = trimmed }; @@ -417,7 +417,7 @@ pub fn noSubstitute(_: std.mem.Allocator, input: []const u8) []const u8 { /// Map a Command to its (tool_name, JSON args) representation. Returns /// null for variants without a 1:1 tool mapping (login, accept_cookies, -/// natural_language, comment, exit, extract — extract is rendered as a +/// natural_language, comment, quit, extract — extract is rendered as a /// custom `eval` script by the caller). /// /// `substitute` is applied to selector-like fields. The `value` field of @@ -447,7 +447,7 @@ pub fn toToolCall(arena: std.mem.Allocator, cmd: Command, substitute: Substitute .tree => .{ .name = @tagName(Action.tree), .args_json = "" }, .markdown => .{ .name = @tagName(Action.markdown), .args_json = "" }, .eval_js => |script| .{ .name = @tagName(Action.eval), .args_json = buildJson(arena, .{ .script = script }) }, - .extract, .exit, .natural_language, .comment, .login, .accept_cookies => null, + .extract, .quit, .natural_language, .comment, .login, .accept_cookies => null, }; } @@ -684,9 +684,9 @@ test "parse TREE" { try std.testing.expect(cmd == .tree); } -test "parse MARKDOWN alias MD" { +test "parse MARKDOWN" { try std.testing.expect(parse("MARKDOWN") == .markdown); - try std.testing.expect(parse("md") == .markdown); + try std.testing.expect(parse("markdown") == .markdown); } test "parse EXTRACT" { @@ -706,11 +706,12 @@ test "parse LOGIN" { test "parse ACCEPT_COOKIES" { try std.testing.expect(parse("ACCEPT_COOKIES") == .accept_cookies); - try std.testing.expect(parse("ACCEPT-COOKIES") == .accept_cookies); + try std.testing.expect(parse("accept_cookies") == .accept_cookies); } -test "parse EXIT" { - try std.testing.expect(parse("EXIT") == .exit); +test "parse QUIT" { + try std.testing.expect(parse("QUIT") == .quit); + try std.testing.expect(parse("quit") == .quit); } test "parse comment" { @@ -747,7 +748,6 @@ test "isRecorded" { try std.testing.expect(parse("EVAL \"1+1\"").isRecorded()); try std.testing.expect(!parse("TREE").isRecorded()); try std.testing.expect(!parse("MARKDOWN").isRecorded()); - try std.testing.expect(!parse("md").isRecorded()); } test "ScriptIterator basic commands" { @@ -1040,7 +1040,7 @@ test "toToolCall: variants without tool mapping return null" { try std.testing.expect(toToolCall(a, .{ .extract = ".x" }, noSubstitute) == null); try std.testing.expect(toToolCall(a, .login, noSubstitute) == null); try std.testing.expect(toToolCall(a, .accept_cookies, noSubstitute) == null); - try std.testing.expect(toToolCall(a, .exit, noSubstitute) == null); + try std.testing.expect(toToolCall(a, .quit, noSubstitute) == null); try std.testing.expect(toToolCall(a, .comment, noSubstitute) == null); try std.testing.expect(toToolCall(a, .{ .natural_language = "hi" }, noSubstitute) == null); } diff --git a/src/agent/CommandExecutor.zig b/src/agent/CommandExecutor.zig index 3d44f067..11ead679 100644 --- a/src/agent/CommandExecutor.zig +++ b/src/agent/CommandExecutor.zig @@ -28,7 +28,7 @@ pub fn executeWithResult(self: *Self, a: std.mem.Allocator, cmd: Command.Command if (cmd == .extract) return self.execExtract(a, cmd.extract); const tc = Command.toToolCall(a, cmd, browser_tools.substituteEnvVars) orelse switch (cmd) { - .exit, .natural_language, .comment, .login, .accept_cookies => unreachable, + .quit, .natural_language, .comment, .login, .accept_cookies => unreachable, else => return .{ .output = "command has no tool mapping", .failed = true }, }; return self.callTool(a, tc.name, tc.args_json); diff --git a/src/agent/Terminal.zig b/src/agent/Terminal.zig index 60d26a04..106a9b88 100644 --- a/src/agent/Terminal.zig +++ b/src/agent/Terminal.zig @@ -30,12 +30,11 @@ const commands = [_]CommandInfo{ .{ .name = "CHECK", .hint = " '' [true|false]" }, .{ .name = "TREE", .hint = "" }, .{ .name = "MARKDOWN", .hint = "" }, - .{ .name = "MD", .hint = "" }, .{ .name = "EXTRACT", .hint = " ''" }, .{ .name = "EVAL", .hint = " '