mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-03-28 15:40:04 +00:00
Merge pull request #1950 from mvanhorn/osc/feat-mcp-action-feedback
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / wba-demo-scripts (push) Has been cancelled
e2e-test / wba-test (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
e2e-test / browser fetch (push) Has been cancelled
zig-test / zig fmt (push) Has been cancelled
zig-test / zig test using v8 in debug mode (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
wpt / zig build release (push) Has been cancelled
wpt / build wpt runner (push) Has been cancelled
wpt / web platform tests json output (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
e2e-integration-test / zig build release (push) Has been cancelled
e2e-integration-test / demo-integration-scripts (push) Has been cancelled
Some checks failed
e2e-test / zig build release (push) Has been cancelled
e2e-test / demo-scripts (push) Has been cancelled
e2e-test / wba-demo-scripts (push) Has been cancelled
e2e-test / wba-test (push) Has been cancelled
e2e-test / cdp-and-hyperfine-bench (push) Has been cancelled
e2e-test / perf-fmt (push) Has been cancelled
e2e-test / browser fetch (push) Has been cancelled
zig-test / zig fmt (push) Has been cancelled
zig-test / zig test using v8 in debug mode (push) Has been cancelled
zig-test / zig test (push) Has been cancelled
zig-test / perf-fmt (push) Has been cancelled
nightly build / build-linux-x86_64 (push) Has been cancelled
nightly build / build-linux-aarch64 (push) Has been cancelled
nightly build / build-macos-aarch64 (push) Has been cancelled
nightly build / build-macos-x86_64 (push) Has been cancelled
wpt / zig build release (push) Has been cancelled
wpt / build wpt runner (push) Has been cancelled
wpt / web platform tests json output (push) Has been cancelled
wpt / perf-fmt (push) Has been cancelled
e2e-integration-test / zig build release (push) Has been cancelled
e2e-integration-test / demo-integration-scripts (push) Has been cancelled
mcp: return page state from click/fill/scroll tools
This commit is contained in:
@@ -103,7 +103,7 @@ pub const tool_list = [_]protocol.Tool{
|
|||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.name = "click",
|
.name = "click",
|
||||||
.description = "Click on an interactive element.",
|
.description = "Click on an interactive element. Returns the current page URL and title after the click.",
|
||||||
.inputSchema = protocol.minify(
|
.inputSchema = protocol.minify(
|
||||||
\\{
|
\\{
|
||||||
\\ "type": "object",
|
\\ "type": "object",
|
||||||
@@ -116,7 +116,7 @@ pub const tool_list = [_]protocol.Tool{
|
|||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.name = "fill",
|
.name = "fill",
|
||||||
.description = "Fill text into an input element.",
|
.description = "Fill text into an input element. Returns the filled value and current page URL and title.",
|
||||||
.inputSchema = protocol.minify(
|
.inputSchema = protocol.minify(
|
||||||
\\{
|
\\{
|
||||||
\\ "type": "object",
|
\\ "type": "object",
|
||||||
@@ -130,7 +130,7 @@ pub const tool_list = [_]protocol.Tool{
|
|||||||
},
|
},
|
||||||
.{
|
.{
|
||||||
.name = "scroll",
|
.name = "scroll",
|
||||||
.description = "Scroll the page or a specific element.",
|
.description = "Scroll the page or a specific element. Returns the scroll position and current page URL and title.",
|
||||||
.inputSchema = protocol.minify(
|
.inputSchema = protocol.minify(
|
||||||
\\{
|
\\{
|
||||||
\\ "type": "object",
|
\\ "type": "object",
|
||||||
@@ -489,7 +489,13 @@ fn handleClick(server: *Server, arena: std.mem.Allocator, id: std.json.Value, ar
|
|||||||
return server.sendError(id, .InternalError, "Failed to click element");
|
return server.sendError(id, .InternalError, "Failed to click element");
|
||||||
};
|
};
|
||||||
|
|
||||||
const content = [_]protocol.TextContent([]const u8){.{ .text = "Clicked successfully." }};
|
const page_title = page.getTitle() catch null;
|
||||||
|
const result_text = try std.fmt.allocPrint(arena, "Clicked element (backendNodeId: {d}). Page url: {s}, title: {s}", .{
|
||||||
|
args.backendNodeId,
|
||||||
|
page.url,
|
||||||
|
page_title orelse "(none)",
|
||||||
|
});
|
||||||
|
const content = [_]protocol.TextContent([]const u8){.{ .text = result_text }};
|
||||||
try server.sendResult(id, protocol.CallToolResult([]const u8){ .content = &content });
|
try server.sendResult(id, protocol.CallToolResult([]const u8){ .content = &content });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,7 +521,14 @@ fn handleFill(server: *Server, arena: std.mem.Allocator, id: std.json.Value, arg
|
|||||||
return server.sendError(id, .InternalError, "Failed to fill element");
|
return server.sendError(id, .InternalError, "Failed to fill element");
|
||||||
};
|
};
|
||||||
|
|
||||||
const content = [_]protocol.TextContent([]const u8){.{ .text = "Filled successfully." }};
|
const page_title = page.getTitle() catch null;
|
||||||
|
const result_text = try std.fmt.allocPrint(arena, "Filled element (backendNodeId: {d}) with \"{s}\". Page url: {s}, title: {s}", .{
|
||||||
|
args.backendNodeId,
|
||||||
|
args.text,
|
||||||
|
page.url,
|
||||||
|
page_title orelse "(none)",
|
||||||
|
});
|
||||||
|
const content = [_]protocol.TextContent([]const u8){.{ .text = result_text }};
|
||||||
try server.sendResult(id, protocol.CallToolResult([]const u8){ .content = &content });
|
try server.sendResult(id, protocol.CallToolResult([]const u8){ .content = &content });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,7 +559,14 @@ fn handleScroll(server: *Server, arena: std.mem.Allocator, id: std.json.Value, a
|
|||||||
return server.sendError(id, .InternalError, "Failed to scroll");
|
return server.sendError(id, .InternalError, "Failed to scroll");
|
||||||
};
|
};
|
||||||
|
|
||||||
const content = [_]protocol.TextContent([]const u8){.{ .text = "Scrolled successfully." }};
|
const page_title = page.getTitle() catch null;
|
||||||
|
const result_text = try std.fmt.allocPrint(arena, "Scrolled to x: {d}, y: {d}. Page url: {s}, title: {s}", .{
|
||||||
|
args.x orelse 0,
|
||||||
|
args.y orelse 0,
|
||||||
|
page.url,
|
||||||
|
page_title orelse "(none)",
|
||||||
|
});
|
||||||
|
const content = [_]protocol.TextContent([]const u8){.{ .text = result_text }};
|
||||||
try server.sendResult(id, protocol.CallToolResult([]const u8){ .content = &content });
|
try server.sendResult(id, protocol.CallToolResult([]const u8){ .content = &content });
|
||||||
}
|
}
|
||||||
fn handleWaitForSelector(server: *Server, arena: std.mem.Allocator, id: std.json.Value, arguments: ?std.json.Value) !void {
|
fn handleWaitForSelector(server: *Server, arena: std.mem.Allocator, id: std.json.Value, arguments: ?std.json.Value) !void {
|
||||||
@@ -685,6 +705,9 @@ test "MCP - Actions: click, fill, scroll" {
|
|||||||
const btn_id_str = std.fmt.bufPrint(&btn_id_buf, "{d}", .{btn_id}) catch unreachable;
|
const btn_id_str = std.fmt.bufPrint(&btn_id_buf, "{d}", .{btn_id}) catch unreachable;
|
||||||
const click_msg = try std.mem.concat(aa, u8, &.{ "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"click\",\"arguments\":{\"backendNodeId\":", btn_id_str, "}}}" });
|
const click_msg = try std.mem.concat(aa, u8, &.{ "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"tools/call\",\"params\":{\"name\":\"click\",\"arguments\":{\"backendNodeId\":", btn_id_str, "}}}" });
|
||||||
try router.handleMessage(server, aa, click_msg);
|
try router.handleMessage(server, aa, click_msg);
|
||||||
|
try testing.expect(std.mem.indexOf(u8, out_alloc.writer.buffered(), "Clicked element") != null);
|
||||||
|
try testing.expect(std.mem.indexOf(u8, out_alloc.writer.buffered(), "Page url: http://localhost:9582/src/browser/tests/mcp_actions.html") != null);
|
||||||
|
out_alloc.clearRetainingCapacity();
|
||||||
|
|
||||||
// Test Fill Input
|
// Test Fill Input
|
||||||
const inp = page.document.getElementById("inp", page).?.asNode();
|
const inp = page.document.getElementById("inp", page).?.asNode();
|
||||||
@@ -693,6 +716,9 @@ test "MCP - Actions: click, fill, scroll" {
|
|||||||
const inp_id_str = std.fmt.bufPrint(&inp_id_buf, "{d}", .{inp_id}) catch unreachable;
|
const inp_id_str = std.fmt.bufPrint(&inp_id_buf, "{d}", .{inp_id}) catch unreachable;
|
||||||
const fill_msg = try std.mem.concat(aa, u8, &.{ "{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/call\",\"params\":{\"name\":\"fill\",\"arguments\":{\"backendNodeId\":", inp_id_str, ",\"text\":\"hello\"}}}" });
|
const fill_msg = try std.mem.concat(aa, u8, &.{ "{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/call\",\"params\":{\"name\":\"fill\",\"arguments\":{\"backendNodeId\":", inp_id_str, ",\"text\":\"hello\"}}}" });
|
||||||
try router.handleMessage(server, aa, fill_msg);
|
try router.handleMessage(server, aa, fill_msg);
|
||||||
|
try testing.expect(std.mem.indexOf(u8, out_alloc.writer.buffered(), "Filled element") != null);
|
||||||
|
try testing.expect(std.mem.indexOf(u8, out_alloc.writer.buffered(), "with \\\"hello\\\"") != null);
|
||||||
|
out_alloc.clearRetainingCapacity();
|
||||||
|
|
||||||
// Test Fill Select
|
// Test Fill Select
|
||||||
const sel = page.document.getElementById("sel", page).?.asNode();
|
const sel = page.document.getElementById("sel", page).?.asNode();
|
||||||
@@ -701,6 +727,9 @@ test "MCP - Actions: click, fill, scroll" {
|
|||||||
const sel_id_str = std.fmt.bufPrint(&sel_id_buf, "{d}", .{sel_id}) catch unreachable;
|
const sel_id_str = std.fmt.bufPrint(&sel_id_buf, "{d}", .{sel_id}) catch unreachable;
|
||||||
const fill_sel_msg = try std.mem.concat(aa, u8, &.{ "{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"tools/call\",\"params\":{\"name\":\"fill\",\"arguments\":{\"backendNodeId\":", sel_id_str, ",\"text\":\"opt2\"}}}" });
|
const fill_sel_msg = try std.mem.concat(aa, u8, &.{ "{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"tools/call\",\"params\":{\"name\":\"fill\",\"arguments\":{\"backendNodeId\":", sel_id_str, ",\"text\":\"opt2\"}}}" });
|
||||||
try router.handleMessage(server, aa, fill_sel_msg);
|
try router.handleMessage(server, aa, fill_sel_msg);
|
||||||
|
try testing.expect(std.mem.indexOf(u8, out_alloc.writer.buffered(), "Filled element") != null);
|
||||||
|
try testing.expect(std.mem.indexOf(u8, out_alloc.writer.buffered(), "with \\\"opt2\\\"") != null);
|
||||||
|
out_alloc.clearRetainingCapacity();
|
||||||
|
|
||||||
// Test Scroll
|
// Test Scroll
|
||||||
const scrollbox = page.document.getElementById("scrollbox", page).?.asNode();
|
const scrollbox = page.document.getElementById("scrollbox", page).?.asNode();
|
||||||
@@ -709,6 +738,8 @@ test "MCP - Actions: click, fill, scroll" {
|
|||||||
const scroll_id_str = std.fmt.bufPrint(&scroll_id_buf, "{d}", .{scrollbox_id}) catch unreachable;
|
const scroll_id_str = std.fmt.bufPrint(&scroll_id_buf, "{d}", .{scrollbox_id}) catch unreachable;
|
||||||
const scroll_msg = try std.mem.concat(aa, u8, &.{ "{\"jsonrpc\":\"2.0\",\"id\":4,\"method\":\"tools/call\",\"params\":{\"name\":\"scroll\",\"arguments\":{\"backendNodeId\":", scroll_id_str, ",\"y\":50}}}" });
|
const scroll_msg = try std.mem.concat(aa, u8, &.{ "{\"jsonrpc\":\"2.0\",\"id\":4,\"method\":\"tools/call\",\"params\":{\"name\":\"scroll\",\"arguments\":{\"backendNodeId\":", scroll_id_str, ",\"y\":50}}}" });
|
||||||
try router.handleMessage(server, aa, scroll_msg);
|
try router.handleMessage(server, aa, scroll_msg);
|
||||||
|
try testing.expect(std.mem.indexOf(u8, out_alloc.writer.buffered(), "Scrolled to x: 0, y: 50") != null);
|
||||||
|
out_alloc.clearRetainingCapacity();
|
||||||
|
|
||||||
// Evaluate assertions
|
// Evaluate assertions
|
||||||
var ls: js.Local.Scope = undefined;
|
var ls: js.Local.Scope = undefined;
|
||||||
|
|||||||
Reference in New Issue
Block a user