mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-06-11 01:25:53 -04:00
eval: auto-serialize non-JSON values in save
This commit is contained in:
@@ -202,7 +202,7 @@ pub const Tool = enum {
|
||||
\\ "url": { "type": "string", "description": "Optional URL to navigate to before evaluating." },
|
||||
\\ "timeout": { "type": "integer", "description": "Optional timeout in milliseconds. Defaults to 10000." },
|
||||
\\ "waitUntil": { "type": "string", "enum": ["load", "domcontentloaded", "networkidle", "done"], "description": "Optional wait strategy. Defaults to 'done'." },
|
||||
\\ "save": { "type": "string", "description": "Optional bridge-store key. The eval's return value is stored under this name and re-exposed as `lp.<name>` to subsequent evals. Objects and arrays are stored as JSON automatically; a returned value must be JSON-serializable." }
|
||||
\\ "save": { "type": "string", "description": "Optional bridge-store key. The eval's return value is stored under this name and re-exposed as `lp.<name>` to subsequent evals. Objects, arrays, and strings are serialized automatically — no JSON.stringify needed." }
|
||||
\\ },
|
||||
\\ "required": ["script"]
|
||||
\\}
|
||||
@@ -966,7 +966,7 @@ fn execEval(arena: std.mem.Allocator, session: *lp.Session, registry: *CDPNode.R
|
||||
// `let`/`const` from leaking; top-level `await`/`return` need the async IIFE.
|
||||
const block_script = std.fmt.allocPrintSentinel(
|
||||
arena,
|
||||
"{{\n{s}\n}}",
|
||||
"{{ {s}\n}}",
|
||||
.{args.script},
|
||||
0,
|
||||
) catch return ToolError.OutOfMemory;
|
||||
@@ -991,14 +991,17 @@ fn execEval(arena: std.mem.Allocator, session: *lp.Session, registry: *CDPNode.R
|
||||
};
|
||||
};
|
||||
|
||||
// Silence on save= success so stdout pipes stay clean.
|
||||
// Silence on save= success so stdout pipes stay clean. Objects/arrays
|
||||
// already render as JSON; a bare string (or other non-JSON text) is
|
||||
// JSON-encoded so it round-trips to `lp.<name>`.
|
||||
if (args.save) |name| {
|
||||
bridgeStoreSet(app_allocator, &session.bridge_store, name, result.text) catch |err| switch (err) {
|
||||
const json_value = if (std.json.validate(arena, result.text) catch false)
|
||||
result.text
|
||||
else
|
||||
std.json.Stringify.valueAlloc(arena, result.text, .{}) catch return ToolError.OutOfMemory;
|
||||
bridgeStoreSet(app_allocator, &session.bridge_store, name, json_value) catch |err| switch (err) {
|
||||
error.OutOfMemory => return ToolError.OutOfMemory,
|
||||
error.InvalidJson => return .{
|
||||
.text = "save= requires the eval to return JSON; wrap with JSON.stringify(...)",
|
||||
.is_error = true,
|
||||
},
|
||||
error.InvalidJson => unreachable,
|
||||
};
|
||||
result = .{ .text = "" };
|
||||
}
|
||||
|
||||
@@ -738,6 +738,43 @@ test "MCP - eval: save= value is readable via lp.<name> in next eval" {
|
||||
} }, out.written());
|
||||
}
|
||||
|
||||
test "MCP - eval: save= a bare string round-trips without JSON.stringify" {
|
||||
defer testing.reset();
|
||||
var out: std.io.Writer.Allocating = .init(testing.arena_allocator);
|
||||
const server = try testLoadPage("about:blank", &out.writer);
|
||||
defer server.deinit();
|
||||
|
||||
const save_msg =
|
||||
\\{
|
||||
\\ "jsonrpc": "2.0",
|
||||
\\ "id": 1,
|
||||
\\ "method": "tools/call",
|
||||
\\ "params": {
|
||||
\\ "name": "eval",
|
||||
\\ "arguments": { "script": "return document.title || 'untitled';", "save": "title" }
|
||||
\\ }
|
||||
\\}
|
||||
;
|
||||
try router.handleMessage(server, testing.arena_allocator, save_msg);
|
||||
|
||||
out.clearRetainingCapacity();
|
||||
const read_msg =
|
||||
\\{
|
||||
\\ "jsonrpc": "2.0",
|
||||
\\ "id": 2,
|
||||
\\ "method": "tools/call",
|
||||
\\ "params": {
|
||||
\\ "name": "eval",
|
||||
\\ "arguments": { "script": "lp.title" }
|
||||
\\ }
|
||||
\\}
|
||||
;
|
||||
try router.handleMessage(server, testing.arena_allocator, read_msg);
|
||||
try testing.expectJson(.{ .id = 2, .result = .{
|
||||
.content = &.{.{ .type = "text", .text = "untitled" }},
|
||||
} }, out.written());
|
||||
}
|
||||
|
||||
test "MCP - eval: lp.* mutations auto-sync between evals" {
|
||||
defer testing.reset();
|
||||
var out: std.io.Writer.Allocating = .init(testing.arena_allocator);
|
||||
|
||||
Reference in New Issue
Block a user