mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-09-15 15:32:03 -04:00
search: track zenai review changes for the keenable engine
zenai's review round made keyless explicit in the client's type (init takes ?[]const u8; null selects the public endpoint) and removed the always-empty description field from results: - the .auto keyless rung and searchExplicit pass null instead of ""; the null-key call is comptime-gated to keyless-capable engines and apiSearch's key parameter is anytype to admit both shapes - a set-but-empty KEENABLE_API_KEY is now keyed and fails loudly instead of silently switching to the keyless rate-limit regime - formatKeenableMarkdown reads snippet only (description no longer exists to fall back to) - build.zig.zon repinned to the reviewed zenai commit
This commit is contained in:
1 parent
6cbe30b088
commit
56e5daed54
2 files changed
+27
-20
No files matched your search
+2
-2
@@ -36,8 +36,8 @@
|
||||
.hash = "sqlite3-3.53.2-DMxLWuAOAAA_Px0arJOIOaP4AKEu5prbsQgPMA35W1zz",
|
||||
},
|
||||
.zenai = .{
|
||||
.url = "git+https://github.com/keenableai/zenai.git#d657a7a5d7c080201ac249b4a1e2cb95981f1bbd",
|
||||
.hash = "zenai-0.0.0-iOY_VBRZBgDgVyBTKY2QfeTorEsE3evpqIBbzrlBONvu",
|
||||
.url = "git+https://github.com/keenableai/zenai.git#8f89838179546d2e26b46be857dbab942ba5e6bd",
|
||||
.hash = "zenai-0.0.0-iOY_VApeBgDxgim4YNZ8UQd3XkAyUGOIrgAMx2pD6zxs",
|
||||
},
|
||||
.isocline = .{
|
||||
.url = "git+https://github.com/arrufat/isocline?ref=lightpanda#832a9fe25f5f4458fcc47b5acc7c21db669c2f47",
|
||||
|
||||
+25
-18
@@ -1028,7 +1028,7 @@ const api_engines = .{
|
||||
},
|
||||
};
|
||||
|
||||
/// Engines that also work with no API key (an empty key routes the client
|
||||
/// Engines that also work with no API key (a `null` key routes the client
|
||||
/// to the provider's public endpoint). `searchExplicit` and the REPL's
|
||||
/// `/searchEngine` warning consult this.
|
||||
pub fn searchEngineKeyless(engine: SearchEngine) bool {
|
||||
@@ -1072,7 +1072,7 @@ fn execSearch(arena: std.mem.Allocator, session: *lp.Session, registry: *CDPNode
|
||||
// set — the loop above already tried it keyed.
|
||||
const kn = api_engines[comptime engineIndex(.keenable)];
|
||||
if (std.c.getenv(kn.env_var) == null) {
|
||||
if (apiSearch(kn, arena, "", args.query)) |markdown_| {
|
||||
if (apiSearch(kn, arena, null, args.query)) |markdown_| {
|
||||
return .{ .text = markdown_ };
|
||||
} else |err| {
|
||||
log.warn(.browser, "keenable keyless fallback", .{ .err = err });
|
||||
@@ -1099,11 +1099,18 @@ fn execSearch(arena: std.mem.Allocator, session: *lp.Session, registry: *CDPNode
|
||||
/// comes back as an error result — no DDG fallback.
|
||||
fn searchExplicit(arena: std.mem.Allocator, comptime engine: anytype, query: []const u8) ToolError!ToolResult {
|
||||
const label = @tagName(engine.tag);
|
||||
const api_key: []const u8 = if (std.c.getenv(engine.env_var)) |z| std.mem.span(z) else if (comptime searchEngineKeyless(engine.tag)) "" else return .{
|
||||
.text = "web search engine is set to " ++ label ++ " but " ++ engine.env_var ++ " is not set in the environment",
|
||||
.is_error = true,
|
||||
};
|
||||
const markdown_ = apiSearch(engine, arena, api_key, query) catch |err| {
|
||||
const markdown_ = blk: {
|
||||
if (std.c.getenv(engine.env_var)) |z|
|
||||
break :blk apiSearch(engine, arena, std.mem.span(z), query);
|
||||
// Comptime-gated so the null-key call is only instantiated for
|
||||
// clients whose `init` takes an optional key.
|
||||
if (comptime searchEngineKeyless(engine.tag))
|
||||
break :blk apiSearch(engine, arena, null, query);
|
||||
return .{
|
||||
.text = "web search engine is set to " ++ label ++ " but " ++ engine.env_var ++ " is not set in the environment",
|
||||
.is_error = true,
|
||||
};
|
||||
} catch |err| {
|
||||
const msg = std.fmt.allocPrint(arena, label ++ " search failed: {s}", .{@errorName(err)}) catch
|
||||
return ToolError.OutOfMemory;
|
||||
return .{ .text = msg, .is_error = true };
|
||||
@@ -1111,11 +1118,13 @@ fn searchExplicit(arena: std.mem.Allocator, comptime engine: anytype, query: []c
|
||||
return .{ .text = markdown_ };
|
||||
}
|
||||
|
||||
/// `arena` owns the returned slice.
|
||||
/// `arena` owns the returned slice. `api_key` is the environment value, or
|
||||
/// `null` for an engine that supports keyless calls (its client's `init`
|
||||
/// takes a `?[]const u8` key — see `searchEngineKeyless`).
|
||||
fn apiSearch(
|
||||
comptime engine: anytype,
|
||||
arena: std.mem.Allocator,
|
||||
api_key: []const u8,
|
||||
api_key: anytype,
|
||||
query: []const u8,
|
||||
) ![]const u8 {
|
||||
var client: engine.Client = .init(lp.io, arena, api_key, engine.init_options);
|
||||
@@ -1176,10 +1185,9 @@ fn formatKeenableMarkdown(w: *std.Io.Writer, resp: keenable.types.SearchResponse
|
||||
return w.writeAll("No results.");
|
||||
}
|
||||
for (resp.results, 0..) |r, i| {
|
||||
// snippet carries the page text; description (the meta description)
|
||||
// is empty on essentially every result and is only a fallback.
|
||||
const snippet = if (r.snippet.len > 0) r.snippet else r.description;
|
||||
try writeResultItem(w, i, r.title, r.url, snippet);
|
||||
// snippet carries the page text (the wire format's always-empty
|
||||
// `description` is deliberately not even mapped by the client).
|
||||
try writeResultItem(w, i, r.title, r.url, r.snippet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2533,17 +2541,16 @@ test "formatBraveMarkdown handles empty results" {
|
||||
try std.testing.expectEqualStrings("No results.", empty_web.written());
|
||||
}
|
||||
|
||||
test "formatKeenableMarkdown reads snippet, falls back to description" {
|
||||
test "formatKeenableMarkdown reads snippet" {
|
||||
var arena: std.heap.ArenaAllocator = .init(std.testing.allocator);
|
||||
defer arena.deinit();
|
||||
const aa = arena.allocator();
|
||||
|
||||
// Real response shape: description present but empty, text in snippet.
|
||||
const resp: keenable.types.SearchResponse = .{
|
||||
.query = "zig",
|
||||
.results = &.{
|
||||
.{ .title = "Zig (programming language)", .url = "https://en.wikipedia.org/wiki/Zig", .snippet = "Zig is a system programming language.", .description = "" },
|
||||
.{ .title = "Zig guide", .url = "https://example.org/zig", .snippet = "", .description = "Meta description only." },
|
||||
.{ .title = "Zig (programming language)", .url = "https://en.wikipedia.org/wiki/Zig", .snippet = "Zig is a system programming language." },
|
||||
.{ .title = "Zig guide", .url = "https://example.org/zig", .snippet = "Compile-time execution." },
|
||||
},
|
||||
};
|
||||
|
||||
@@ -2553,7 +2560,7 @@ test "formatKeenableMarkdown reads snippet, falls back to description" {
|
||||
try std.testing.expect(std.mem.indexOf(u8, md, "1. **Zig (programming language)**") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, md, "Zig is a system programming language.") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, md, "2. **Zig guide**") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, md, "Meta description only.") != null);
|
||||
try std.testing.expect(std.mem.indexOf(u8, md, "Compile-time execution.") != null);
|
||||
}
|
||||
|
||||
test "formatKeenableMarkdown handles empty results" {
|
||||
|
||||
Reference in new issue
Block a user