Skip to content

v0.9.46

Latest

Choose a tag to compare

@Goldentrii Goldentrii released this 06 Nov 08:42
· 5 commits to main since this release
f35b8f8

OpenAI plugin review release. Search, research, and Google scraping return real destination URLs instead of Google's relative click-tracking links; tool descriptions drop comparative wording; and the hosted endpoint serves ChatGPT/OpenAI clients a reviewed 17-tool surface on the same URL.

Changed

  • Tool descriptions no longer compare options with evaluative wording (OpenAI plugin review flagged novada_search's description as comparing/preferring; applied to every client, not only OpenAI). Removed superlatives, magnitude claims, and "cheaper/faster than X" phrasing — e.g. novada_search's "(faster, more thorough)" and "fastest/most reliable … slower fallbacks", novada_extract's "15-100x faster on static sites", novada_crawl's "novada_map — much faster", novada_research's "novada_search — faster/cheaper", the SERP scrapers' "cheaper than a raw-SERP scrape" / "raw SERP dump", novada_proxy's "strongest"/"fastest/cheapest", and "slower" in three render/max_depth parameter descriptions. Routing guidance stays ("use novada_research for…"), and neutral facts about our own options stay ("adds rendering time"). novada_scrape_perplexity no longer mentions the broken chatgpt.com scraper. Tier A tool-selection eval unchanged (60% exact / 64% acceptable, identical per-task picks).
  • Cross-references to sibling tools are marked up for per-surface rendering ({{sibling:…}}, _core/description_surface.ts): mentions of novada_scrape, novada_map, and novada_monitor in other tools' descriptions are dropped on a surface that does not list those tools. No visible change on npm or the default hosted surface.

Added (hosted server — mcp.novada.com, not part of the npm package)

  • Per-client tool surface for OpenAI (hosted-server/vercel/api/_surface.ts). The same https://mcp.novada.com/mcp URL now serves OAuth clients whose registered redirect URIs are on chatgpt.com or openai.com (exact host or subdomain, https only) a 17-tool surface: search, extract, crawl, research, the Google/Bing/DuckDuckGo/Yandex/Amazon/Walmart/Perplexity/YouTube/GitHub scrapers, proxy, ai_monitor, account, proxy_account_list. On that surface the platform scrapers are annotated readOnlyHint: false (each call queues an upstream scrape job), descriptions drop mentions of tools it does not list, hidden backward-compat aliases are not callable, the one-time onboarding notice (it advertises free credits) is not appended, error guidance does not point at the local npm server, and initialize returns routing instructions. The surface is resolved per request from the access token's client_id (cached per process; client records are immutable), so already-connected clients switch without reconnecting. API-key callers and every other OAuth client keep the unchanged 29-tool surface. config/surfaces.json gains an openai entry; scripts/check-hosted-drift.mjs gate (d) requires it to equal the code list and stay a subset of hosted.

Changed (hosted server)

  • POST /register accepts token_endpoint_auth_method client_secret_post / client_secret_basic and registers the client as public ("none" in the response, no secret issued) instead of returning 400; /token takes client_id from an HTTP Basic header when the body omits it.
  • /mcp CORS preflight allows the mcp-protocol-version header.
  • 401 responses no longer mention "$10 free credits" (they still point to https://novada.com for a key): these are pre-auth responses, so the caller's client is unknown and the wording cannot be scoped to non-OpenAI clients.
  • The hosted wall-clock timeout's resume hint names the tool to re-call (the platform scraper itself), instead of always novada_scrape.

Fixed

  • novada_search, novada_research, and novada_scrape_google no longer return Google click-tracking "goto" redirects as a relative path (e.g. link: "/goto?url=CAES..."). Reproduced live against production scraper.novada.com (2026-11-04): a 5-result novada_search call returned 9 /goto?url= occurrences, and novada_research's extraction step — which calls novadaExtract({url: source.url}) on the raw link — failed for every such source (sources_extracted: 0 full + N snippet-only), since a relative path is not a fetchable URL. A new shared resolver (src/utils/google_redirect.ts) resolves every Google-wrapped link to its real destination. When the upstream result carries a redirect_link (https://www.google.com/url?sa=t&...&url=<token>&ved=...), its full query is replayed verbatim against Google's /url endpoint and the destination is read from the page's var redirectUrl / <meta refresh> — one request per result. Live-measured 2026-11-05: for fresh tokens, Google's /goto?url=<token> answered with its "verifying your request" interstitial instead of a 302 for 4/4 tokens, while the /url replay resolved 4/4 from both a residential IP and the production EC2 host; end-to-end, 3 spaced searches resolved 12 of 13 wrapped results (the same queries before this change: 6 of 14). The /goto?url=<token> 302 remains the second path, and when it returns the interstitial the resolver follows its embedded continuation token exactly once (the token is JS-escaped as url\x3d... in the page). A bare /url?url=<token> request (without the rest of the query) is never sent — it only ever returns a generic notice page. A result that still cannot be resolved is KEPT with its title and snippet but no link (url_unavailable: true) — never a relative path; when every result in a batch is unresolvable the response says so explicitly (url_resolution_warning). Decoding the opaque token locally (no network call) was investigated and rejected — it base64url-decodes to an encrypted protobuf blob with no recoverable URL. Wired into novada_search/novada_research (search.ts's parseAndResolveScraperSearchResults, the one choke point both share) and into novada_scrape_google/novada_scrape(platform="google.com") (the generic scrape.ts engine, a separate raw-record code path). Unresolved links are counted (goto_links_unresolved in json, an Agent Hints line in markdown/csv/html/toon). Every outbound request targets hardcoded https://www.google.com/{goto,url} URLs; a token is only taken from a Google redirect host, so an upstream link on any other host is never fetched. Zero network-call / zero-diff for every record whose link is already a plain absolute URL — i.e. every other platform's scrape output, and most Google results too.
  • novada_scrape_google (and novada_scrape(platform="google.com")) no longer leak raw base64 favicon/image data in json and markdown output. A Google organic result's favicon field (and the nested about_this_result.source.icon) is a data:image/png;base64,... blob, live-measured at ~19KB EACH — csv/excel/html already dropped these columns via curateTabularRecords; json and markdown rendered them raw. A new recursive stripBase64Blobs() (reusing the same isBase64Blob detector) replaces any base64-blob value with a short [base64 image data stripped] marker in those two formats only; csv/excel/html's existing column-drop behavior is unchanged.
  • novada_search's time_range/start_date/end_date params now actually filter Google and DuckDuckGo results. Live-verified (2026-11-04) that the previous implementation sent a literal time_range=week form field to the upstream google_search scraper, which silently ignored it — a time_range="week" query returned results dated from 2025 and 2026 months out, not the last 7 days. The google.com engine now maps to Google's own tbs=qdr:{d|w|m|y} (relative) or tbs=cdr:1,cd_min:M/D/YYYY,cd_max:M/D/YYYY (custom range, when start_date/end_date is given — wins over time_range); both shapes were live-verified against known date windows. The duckduckgo.com engine now maps to df={d|w|m|y} (the catalog's own declared enum for this op). The yandex.com engine's equivalent (within, enum ["0","77","1","2"]) is NOT self-evidently a day/week/month/year encoding and was left unmapped (same pre-existing, documented no-op) rather than guess at an unverified code — see reports/search-goto-links-2026-11-04.md for the open follow-up.