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%
1/**2 * Search-box.ai3 * Author: Simon-Pierre Boucher4 * Contact: contact@spboucher.ai5 * File: packages/events/src/index.ts6 * Description: Typed research event protocol streamed from backend to UI.7 */89import type {10 Claim,11 Contradiction,12 Evidence,13 SessionStatus,14 Source15} from "@search-box/shared";1617/**18 * Every UI update corresponds to exactly one of these events, persisted in19 * order (monotonic `seq`) so streams can be replayed via Last-Event-ID.20 */21export type ResearchEventPayload =22 | { type: "session.started"; question: string }23 | { type: "session.status"; status: SessionStatus }24 | { type: "session.completed"; answer: string }25 | { type: "session.failed"; error: string }26 | { type: "plan.updated"; objectives: string[]; publicReason: string }27 | { type: "thought"; publicReason: string }28 | {29 type: "action.started";30 actionId: string;31 kind: "search" | "fetch";32 label: string;33 input: Record<string, unknown>;34 }35 | {36 type: "action.completed";37 actionId: string;38 kind: "search" | "fetch";39 ok: boolean;40 summary: string;41 latencyMs: number;42 }43 | { type: "source.added"; source: Source }44 | { type: "source.updated"; source: Source }45 | { type: "evidence.added"; evidence: Evidence; sourceUrl: string; sourceTitle: string | null }46 | { type: "claim.added"; claim: Claim }47 | { type: "claim.updated"; claim: Claim }48 | { type: "contradiction.added"; contradiction: Contradiction }49 | { type: "budget.updated"; usage: Record<string, number>; limits: Record<string, number> }50 | { type: "synthesis.started" }51 | { type: "answer.delta"; delta: string }52 | { type: "answer.completed"; answer: string; citations: CitationMapEntry[] };5354export interface CitationMapEntry {55 index: number;56 sourceId: string;57 url: string;58 title: string | null;59}6061export interface ResearchEvent {62 id: string;63 sessionId: string;64 seq: number;65 createdAt: string;66 payload: ResearchEventPayload;67}6869export type ResearchEventType = ResearchEventPayload["type"];70