$ cat node-template.py
W
Web Search
// Search the public web (via Brave Search) and return a ranked list of result URLs (no snippets — deliberate, to avoid SERP-snippet hallucination). The output is a URL list; reading the content behind those URLs is a separate concern handled downstream. Pairs with: `Fetch URL as Markdown`.
Input
Integration
#web#search#brave#research
template.py
1"""2Web Search34Thin shim over the gais.web SDK namespace. Sends a query to Brave Search via5the gais-web sidecar service and returns a ranked list of URLs (no snippets).6Workflow authors typically pair this with the Fetch URL as Markdown node to7build research-agent loops.8"""910from __future__ import annotations1112import json13import sys14import traceback15from typing import Any1617from gais import Gais181920def main() -> None:21 try:22 envelope = json.loads(sys.stdin.read() or "{}")23 inputs: dict[str, Any] = (24 envelope.get("inputs", {}) if isinstance(envelope, dict) else {}25 )2627 query = inputs.get("query")28 num_results = inputs.get("num_results", 10)29 country_raw = inputs.get("country", "any")3031 if not query:32 raise ValueError("Required input 'query' not provided")3334 # Normalize the "Any" sentinel (and any legacy empty-string default)35 # to None so the SDK omits the country param. The sentinel is "any"36 # rather than "" because Radix Select.Item rejects empty-string37 # values (reserved for clearing the selection).38 country = country_raw if country_raw and country_raw != "any" else None3940 print(41 f"[web-search] query={query!r} num_results={num_results} country={country!r}",42 file=sys.stderr,43 )4445 result = Gais.web.search(46 query=query,47 num_results=num_results,48 country=country,49 )5051 urls = result.metadata.get("urls", [])52 result_count = result.metadata.get("result_count", len(urls) if isinstance(urls, list) else 0)53 rate_limited = result.metadata.get("rate_limited", False)5455 print(56 f"[web-search] done result_count={result_count} rate_limited={rate_limited}",57 file=sys.stderr,58 )5960 json.dump(61 {62 "urls": urls,63 "result_count": result_count,64 "rate_limited": rate_limited,65 },66 sys.stdout,67 )68 except Exception as e:69 error = {70 "error": str(e),71 "errorType": type(e).__name__,72 "traceback": traceback.format_exc(),73 }74 print(json.dumps(error), file=sys.stderr)75 sys.exit(1)767778if __name__ == "__main__":79 main()80$ git log --oneline
v1.0.5
HEAD
2026-05-25v1.0.42026-05-25
v1.0.32026-05-22
v1.0.22026-05-21
v1.0.12026-05-21
v1.0.02026-05-21