Overhaul docs retrieval and web search quality
Replace the abandoned llms-txt-mcp/Chroma docs backend with an in-repo MCP service: SQLite WAL + FTS5 + sentence-transformer embeddings, transactional source replacement, persisted state across restarts, singleflight refresh with conditional requests, hybrid lexical/semantic ranking with exact-duplicate collapse, source/host filters, and explicit-by-default content retrieval. Add docs_rebuild and a docs-rebuild CLI command. Add deterministic llms-full.txt snapshot generation for machine-local menus with hash-validated provenance manifests; lifecycle commands promote a local menu to its snapshot only when the manifest validates. Switch public source profiles to content-bearing llms-full.txt feeds. Improve web search: bounded provider fallback with per-attempt diagnostics and cancellation, an optional Brave Search API provider, strict SearXNG engine selection, capped link/media extraction, and a real engine=browser renderer that routes every request through the existing SSRF vetting while blocking WebSockets, non-GET traffic, and private destinations. Extend release checks with offline unit suites and isolated candidate container tests for both images.
This commit is contained in:
59
scripts/test-web-search-candidate.mjs
Normal file
59
scripts/test-web-search-candidate.mjs
Normal file
@@ -0,0 +1,59 @@
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
import { probeMcp, rpc } from "../docker/web-search/mcp-probe.mjs";
|
||||
|
||||
const url = process.argv[2];
|
||||
if (!url) throw new Error("usage: node scripts/test-web-search-candidate.mjs <mcp-url>");
|
||||
|
||||
await probeMcp(url, { timeoutMs: 10_000 });
|
||||
|
||||
function payload(result) {
|
||||
const text = (result.content || []).find(part => part.type === "text")?.text;
|
||||
return text ? JSON.parse(text) : result.structuredContent;
|
||||
}
|
||||
|
||||
const search = payload(await rpc(url, 3, "tools/call", {
|
||||
name: "search_web",
|
||||
arguments: { q: "candidate diagnostic fixture", limit: 3, provider: "searxng" }
|
||||
}, 30_000));
|
||||
assert.equal(search.items[0].title, "Deterministic Search Result");
|
||||
assert.equal(search.providerUsed, "searxng");
|
||||
assert.equal(search.diagnostics.attempts[0].status, "success");
|
||||
assert.equal(search.diagnostics.attempts[0].result_count, 1);
|
||||
|
||||
const httpFetch = payload(await rpc(url, 4, "tools/call", {
|
||||
name: "fetch_url",
|
||||
arguments: { url: "http://mock-search.test:8080/dynamic", engine: "http", format: "text" }
|
||||
}, 30_000));
|
||||
assert(!httpFetch.content.includes("BROWSER_RENDERED_MARKER"));
|
||||
|
||||
const browserFetch = payload(await rpc(url, 5, "tools/call", {
|
||||
name: "fetch_url",
|
||||
arguments: { url: "http://mock-search.test:8080/dynamic", engine: "browser", format: "text", timeout_ms: 20_000 }
|
||||
}, 60_000));
|
||||
assert(browserFetch.content.includes("BROWSER_RENDERED_MARKER"));
|
||||
|
||||
const blocked = await rpc(url, 6, "tools/call", {
|
||||
name: "fetch_url",
|
||||
arguments: { url: "http://127.0.0.1:8765/private", engine: "browser" }
|
||||
}, 30_000);
|
||||
assert.equal(blocked.isError, true);
|
||||
assert((blocked.content || []).some(part => part.text?.includes("Blocked localhost/private URL")));
|
||||
|
||||
const blockedRedirect = await rpc(url, 7, "tools/call", {
|
||||
name: "fetch_url",
|
||||
arguments: { url: "http://mock-search.test:8080/redirect-private", engine: "browser" }
|
||||
}, 30_000);
|
||||
assert.equal(blockedRedirect.isError, true);
|
||||
|
||||
await rpc(url, 8, "tools/call", {
|
||||
name: "fetch_url",
|
||||
arguments: { url: "http://mock-search.test:8080/websocket-attempt", engine: "browser", fresh: true }
|
||||
}, 30_000);
|
||||
const websocketCount = payload(await rpc(url, 9, "tools/call", {
|
||||
name: "fetch_url",
|
||||
arguments: { url: "http://mock-search.test:8080/ws-count", engine: "http", format: "text", fresh: true }
|
||||
}, 30_000));
|
||||
assert.equal(websocketCount.content.trim(), "0");
|
||||
|
||||
console.log("pass web-search candidate diagnostics, browser rendering, and SSRF rejection");
|
||||
Reference in New Issue
Block a user