mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-06-11 01:25:53 -04:00
script: unwrap only __root sentinel in extract
Only unwrap the `__root` sentinel injected for array schemas, ensuring single-field object schemas retain their shape. Also update synthesis prompt instructions for modern JS and tool fidelity.
This commit is contained in:
@@ -127,6 +127,17 @@ pub const save_synthesis_prompt =
|
||||
\\JavaScript wherever they fit; fall back to evaluate(...) only for logic the
|
||||
\\builtins can't express. End with an extract(...) for any data the user
|
||||
\\wanted out.
|
||||
\\Stay faithful to the recorded tool calls: reproduce each call with the same
|
||||
\\options it actually used. Do NOT add `timeout` or `waitUntil` to goto (or any
|
||||
\\tool) unless that option was used in the session — default calls stay default.
|
||||
\\Use evaluate(...) only when no builtin can express the logic. Never stash a
|
||||
\\result into `lp.*` and read it back, and never append no-op extract(...) probes
|
||||
\\or trailing `evaluate("return lp....")` lines — the script's output is whatever
|
||||
\\the final extract(...) (plus any plain-JS aggregation) produces.
|
||||
\\Write modern, readable JavaScript: `for (const x of xs)` rather than
|
||||
\\`for (var i = 0; i < xs.length; i++)`, `const`/`let` over `var`, template
|
||||
\\literals, destructuring. Indent consistently with 2 spaces, including
|
||||
\\multi-line extract({...}) schema literals.
|
||||
\\The output MUST be valid JavaScript that runs as-is — it is executed as a
|
||||
\\classic script (not a module), so top-level `await` is a syntax error;
|
||||
\\`await` is only legal inside an `async` function.
|
||||
|
||||
@@ -514,6 +514,8 @@ fn objectWith(arena: std.mem.Allocator, key: []const u8, value: std.json.Value)
|
||||
return .{ .object = obj };
|
||||
}
|
||||
|
||||
/// Unwraps only the `__root` sentinel that `normalizeExtractSchemaString` injects
|
||||
/// for array schemas; a real single-field object schema keeps its shape.
|
||||
fn normalizeExtractReturnJson(_: *Runtime, arena: std.mem.Allocator, value: []const u8) error{OutOfMemory}![]const u8 {
|
||||
if (value.len == 0) return value;
|
||||
|
||||
@@ -525,7 +527,7 @@ fn normalizeExtractReturnJson(_: *Runtime, arena: std.mem.Allocator, value: []co
|
||||
|
||||
var it = parsed.object.iterator();
|
||||
const entry = it.next() orelse return value;
|
||||
if (entry.value_ptr.* != .array) return value;
|
||||
if (!std.mem.eql(u8, entry.key_ptr.*, "__root")) return value;
|
||||
return try std.json.Stringify.valueAlloc(arena, entry.value_ptr.*, .{});
|
||||
}
|
||||
|
||||
@@ -691,8 +693,8 @@ test "agent script runtime: extract returns a JavaScript object" {
|
||||
\\ }
|
||||
\\ }]
|
||||
\\});
|
||||
\\if (!Array.isArray(options)) throw new Error("single array field should return an array");
|
||||
\\if (options[0].text !== "Option 1") throw new Error("unexpected unwrapped option text: " + options[0].text);
|
||||
\\if (typeof options !== "object" || options === null || Array.isArray(options)) throw new Error("single object field should stay an object");
|
||||
\\if (options.options[0].text !== "Option 1") throw new Error("unexpected option text: " + options.options[0].text);
|
||||
\\const direct = extract([{ selector: "#sel option", limit: 1 }]);
|
||||
\\if (!Array.isArray(direct)) throw new Error("array schema should return an array");
|
||||
\\if (direct[0] !== "Option 1") throw new Error("unexpected direct array extract: " + direct[0]);
|
||||
|
||||
Reference in New Issue
Block a user