mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-10-09 12:51:45 -04:00
agent: add /clear and /reset REPL commands
- `/clear` forgets conversation history, usage, and node IDs while keeping the loaded page and cookies. - `/reset` does a full reset, starting a fresh browser session.
This commit is contained in:
1 parent
2d2914e878
commit
c355b0bda8
3 files changed
+53
-4
No files matched your search
+4
-1
@@ -307,7 +307,10 @@ See [agent-script.md](agent-script.md) for the full script format reference.
|
||||
the REPL, `/verbosity <low|medium|high>` tunes the log level,
|
||||
`/effort <none|minimal|low|medium|high|xhigh>` sets the per-turn reasoning
|
||||
budget (saved to `.lp-agent.zon`), and `/usage` prints cumulative token usage
|
||||
and the cache hit rate for the session. These are REPL-only and never recorded.
|
||||
and the cache hit rate for the session — `/clear` forgets the conversation
|
||||
(history, usage, recorded actions, node IDs) while keeping the loaded page and
|
||||
cookies, and `/reset` goes further by also starting a fresh browser session,
|
||||
dropping the page, cookies, storage, and history. These are REPL-only and never recorded.
|
||||
```
|
||||
> /goto https://example.com
|
||||
> /findElement role=button name=Submit
|
||||
|
||||
+46
-2
@@ -321,8 +321,7 @@ pub fn init(allocator: std.mem.Allocator, app: *App, opts: Config.Agent) !*Agent
|
||||
try self.browser.init(app, .{}, null);
|
||||
errdefer self.browser.deinit();
|
||||
|
||||
self.session = try self.browser.newSession(notification);
|
||||
self.session.cancel_hook = .{ .context = @ptrCast(self), .check = checkCancel };
|
||||
try self.startSession();
|
||||
|
||||
self.ai_client = if (llm) |l| try zenai.provider.Client.init(allocator, l, .{ .base_url = opts.base_url, .retry_policy = .long_running }) else null;
|
||||
errdefer if (self.ai_client) |c| c.deinit(allocator);
|
||||
@@ -361,6 +360,13 @@ pub fn deinit(self: *Agent) void {
|
||||
self.allocator.destroy(self);
|
||||
}
|
||||
|
||||
/// Create a fresh browser session and wire its cancel hook back to this agent
|
||||
/// so Ctrl-C aborts in-flight page work. Used at startup and by `/reset`.
|
||||
fn startSession(self: *Agent) !void {
|
||||
self.session = try self.browser.newSession(self.notification);
|
||||
self.session.cancel_hook = .{ .context = @ptrCast(self), .check = checkCancel };
|
||||
}
|
||||
|
||||
// Tool definitions are compile-time constant; project them once per process.
|
||||
var global_tools_storage: [browser_tools.tool_defs.len]ProviderTool = undefined;
|
||||
var global_tools_once = std.once(initGlobalTools);
|
||||
@@ -634,6 +640,8 @@ fn handleMeta(self: *Agent, arena: std.mem.Allocator, meta: *const SlashCommand.
|
||||
.verbosity => self.handleVerbosity(rest),
|
||||
.effort => self.handleEffort(rest),
|
||||
.usage => self.handleUsage(),
|
||||
.clear => self.handleClear(),
|
||||
.reset => self.handleReset(),
|
||||
.save => self.handleSave(arena, rest),
|
||||
.load => self.handleLoad(rest),
|
||||
.model => self.handleModel(arena, rest),
|
||||
@@ -690,6 +698,34 @@ fn handleUsage(self: *Agent) void {
|
||||
}
|
||||
}
|
||||
|
||||
/// Drop everything tied to the conversation: history (the system prompt
|
||||
/// re-seeds lazily on the next turn), cumulative usage, the recorded action
|
||||
/// buffer, and DOM node IDs. Shared by `/clear` and `/reset`.
|
||||
fn clearConversation(self: *Agent) void {
|
||||
self.rollbackMessages(0);
|
||||
self.save_buffer.reset();
|
||||
self.total_usage = .{};
|
||||
self.node_registry.reset();
|
||||
}
|
||||
|
||||
/// Forget the conversation while leaving the browser session live — the loaded
|
||||
/// page stays put and cookies/logins are preserved.
|
||||
fn handleClear(self: *Agent) void {
|
||||
self.clearConversation();
|
||||
self.terminal.printInfo("Cleared conversation, usage, and node IDs. Page and cookies kept.", .{});
|
||||
}
|
||||
|
||||
/// Full clean slate: everything `/clear` drops, plus a fresh browser session,
|
||||
/// so the loaded page, cookies, storage, and history are gone too.
|
||||
fn handleReset(self: *Agent) void {
|
||||
self.startSession() catch |err| {
|
||||
self.terminal.printError("reset failed: {s}", .{@errorName(err)});
|
||||
return;
|
||||
};
|
||||
self.clearConversation();
|
||||
self.terminal.printInfo("Reset conversation and browser session. Page, cookies, and storage cleared.", .{});
|
||||
}
|
||||
|
||||
fn handleLoad(self: *Agent, rest: []const u8) void {
|
||||
const path = std.mem.trim(u8, rest, &std.ascii.whitespace);
|
||||
if (path.len == 0) {
|
||||
@@ -1173,6 +1209,14 @@ fn printSlashHelp(self: *Agent, arena: std.mem.Allocator, target: []const u8) vo
|
||||
"/usage — show cumulative token usage and cache hit rate for this session",
|
||||
.{},
|
||||
),
|
||||
.clear => self.terminal.printInfo(
|
||||
"/clear — forget the conversation (history, usage, recorded actions, node IDs); keeps the loaded page and cookies",
|
||||
.{},
|
||||
),
|
||||
.reset => self.terminal.printInfo(
|
||||
"/reset — full reset: everything /clear does plus a new browser session, dropping the page, cookies, storage, and history",
|
||||
.{},
|
||||
),
|
||||
.save => self.terminal.printInfo(
|
||||
"/save [filename.js] [prompt] — save the session to [filename.js] (a random session-*.js if omitted). With an LLM, synthesizes an idiomatic script from the session and the optional prompt; with --no-llm, dumps the recorded actions verbatim.",
|
||||
.{},
|
||||
|
||||
@@ -47,7 +47,7 @@ pub const MetaCommand = struct {
|
||||
|
||||
/// Dispatched by `Agent.handleMeta` via an exhaustive switch so adding
|
||||
/// a new meta command is a compile error until it's wired up there too.
|
||||
const Tag = enum { help, quit, verbosity, effort, usage, save, load, model, provider };
|
||||
const Tag = enum { help, quit, verbosity, effort, usage, clear, reset, save, load, model, provider };
|
||||
};
|
||||
|
||||
pub const meta_commands = [_]MetaCommand{
|
||||
@@ -56,6 +56,8 @@ pub const meta_commands = [_]MetaCommand{
|
||||
.{ .tag = .verbosity, .name = "verbosity", .hint = "<low|medium|high>", .values = &.{ "low", "medium", "high" }, .description = "Set agent verbosity" },
|
||||
.{ .tag = .effort, .name = "effort", .hint = "<none|minimal|low|medium|high|xhigh>", .values = &.{ "none", "minimal", "low", "medium", "high", "xhigh" }, .description = "Set per-turn reasoning effort" },
|
||||
.{ .tag = .usage, .name = "usage", .hint = "", .values = &.{}, .description = "Show token usage and cache stats for this session" },
|
||||
.{ .tag = .clear, .name = "clear", .hint = "", .values = &.{}, .description = "Clear conversation history and usage (keeps page/cookies)" },
|
||||
.{ .tag = .reset, .name = "reset", .hint = "", .values = &.{}, .description = "Reset conversation and browser session (drops page/cookies)" },
|
||||
.{ .tag = .save, .name = "save", .hint = "[filename.js] [prompt]", .values = &.{}, .description = "Save this session to a file" },
|
||||
.{ .tag = .load, .name = "load", .hint = "<path>", .values = &.{}, .description = "Load and run a script from disk" },
|
||||
.{ .tag = .model, .name = "model", .hint = "[name]", .values = &.{}, .description = "Change the model" },
|
||||
|
||||
Reference in new issue
Block a user