SPB Git

spb/search-box Public

Agentic web research engine — hypotheses, verbatim evidence, contradictions, sourced answers streamed live. Claude Opus 5 + Firecrawl + PostgreSQL.

TypeScript 76.9% CSS 18.7% SQL 2.1% JavaScript 1.8% Shell 0.5%
2.3 KB

# Agent loop

packages/agent/src/orchestrator.ts runs a manual Claude tool-use loop:

  1. One streaming Messages API call per turn (effort: medium, prompt-cached system).
  2. All tool_use blocks in the response execute sequentially; all results return in one user message (assistant content — thinking blocks included — is echoed back verbatim).
  3. The loop ends when the model calls finish_research, stops calling tools, or budgets run out (one warning turn, then hard stop).

# Tools

Tool Effect
set_objectives research plan (emits plan.updated)
web_search Firecrawl search; results become found sources
fetch_url Firecrawl scrape → stored (≤120k chars), returned to model (≤14k) wrapped in <untrusted_web_content>
read_source re-read stored content with offset paging — costs no budget
add_claim / update_claim hypothesis lifecycle with confidence 0..1
add_evidence verbatim quote tied to claim + stance; soft-verified against stored content
add_contradiction first-class disagreement record
report_progress public narration (thought event)
finish_research closes the loop, hands off to synthesis

# Safety

  • Budgets (maxSearches, maxScrapes, maxToolCalls, maxModelTurns, deadlineMs) are hard bounds enforced by the app, not suggestions to the model.
  • Tool inputs are zod-validated; invalid input returns an is_error tool result and the session continues (a single tool failure never kills a session).
  • Scraped content is wrapped in <untrusted_web_content> and the system prompt instructs the model to treat it as evidence, never as instructions (prompt-injection defense).
  • URLs pass an SSRF guard (packages/firecrawl/src/url-guard.ts) blocking private ranges, localhost and metadata endpoints.
  • stop_reason: "refusal" fails the session gracefully with a user-visible error.

# Synthesis

packages/agent/src/synthesis.ts assigns mechanical citation indices, builds the evidence base (claims → stances → verbatim quotes labeled [n]), and streams the answer token-by-token (answer.delta events, buffered ~160 chars / 400 ms per event row).