Skip to content
/ Roth Public

A multi-LLM system that runs natively on your browser with search capability.

Notifications You must be signed in to change notification settings

vmanvs/Roth

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

13 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Roth AI

On-Device AI Assistant with Web Search Capabilities

Roth is a privacy-focused AI chat application that runs entirely in your browser using WebGPU. It features a multi-model orchestration pipeline with optional web search integration via a companion Chrome extension.


🌐 Live Demo

The application is hosted at: rothai.netlify.app


πŸ“‘ Index


✨ Features

Feature Description
100% Client-Side All AI models run locally in your browser using WebGPU. No data sent to servers.
Model Caching Models are downloaded once and then cached in your browser's Cache API for instant subsequent loads.
Multi-Model Pipeline Uses Halugate Sentinel for query classification and Qwen3 for reasoning/generation.
Web Search Integration Optional Chrome extension enables real-time DuckDuckGo searches to ground responses in facts.
Streaming Markdown Real-time markdown rendering with syntax highlighting as the AI generates responses.
Think Tag Support Displays AI reasoning in a collapsible panel, separating thought process from final answer.
Neomorphic UI Modern dark theme with pronounced shadows and responsive mobile layout.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                           BROWSER (WebGPU)                          β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚
β”‚  β”‚  tinkering  │───▢│   orchestrator  │───▢│  markdown-renderer  β”‚  β”‚
β”‚  β”‚    .ts      β”‚    β”‚      .ts        β”‚    β”‚        .ts          β”‚  β”‚
β”‚  β”‚  (Main App) β”‚    β”‚ (State Machine) β”‚    β”‚ (Real-time Render)  β”‚  β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚
β”‚                              β”‚                                       β”‚
β”‚                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”                            β”‚
β”‚                    β”‚ extension-bridge  │◀────┐                      β”‚
β”‚                    β”‚       .ts         β”‚     β”‚                      β”‚
β”‚                    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     β”‚                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                               β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                     CHROME EXTENSION         β”‚                      β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”‚β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     β”‚                      β”‚
β”‚  β”‚ content.js  │◀──▢│  background.js   β”‚β”€β”€β”€β”€β”€β”˜                      β”‚
β”‚  β”‚ (DOM Bridge)β”‚    β”‚ (Service Worker) β”‚                            β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                            β”‚
β”‚                              β”‚                                       β”‚
β”‚                              β–Ό                                       β”‚
β”‚                    [ DuckDuckGo API ]                               β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”Œ Usage of Extension

The Roth Search Helper extension enables web search without compromising privacy.

How to enable search

  1. Installation: When prompted by the onboarding modal, click the "Enable Search" button.
  2. Direct Link: Alternatively, you can download the extension from the Chrome Web Store: Roth Search Helper.
  3. Reload: After installing the extension, you must reload the page for the extension to be detected and full mode to be initialized.
File Purpose
background.js Service worker that fetches raw HTML from DuckDuckGo.
content.js Parses HTML using DOMParser, filters ads, limits to 3 results, and relays to the page.
manifest.json Manifest V3 configuration with host_permissions for DuckDuckGo.

πŸ“ Project Structure

roth/
β”œβ”€β”€ index.html              # Main HTML entry point
β”œβ”€β”€ styles.css              # Neomorphic UI styles (design tokens, responsive)
β”œβ”€β”€ tinkering.ts            # Main application logic (model loading, UI events)
β”œβ”€β”€ build.ts                # Bun build script
β”œβ”€β”€ _headers                # Netlify headers for COOP/COEP (SharedArrayBuffer)
β”‚
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ orchestrator.ts     # Multi-model pipeline state machine
β”‚   β”œβ”€β”€ extension-bridge.ts # Chrome extension communication layer
β”‚   β”œβ”€β”€ streaming-parser.ts # FSM for <think> tag extraction
β”‚   └── markdown-renderer.ts# Real-time markdown streaming with highlight.js
β”‚
β”œβ”€β”€ extension/
β”‚   β”œβ”€β”€ manifest.json       # Chrome extension manifest (Manifest V3)
β”‚   β”œβ”€β”€ background.js       # Service worker for DuckDuckGo fetch
β”‚   β”œβ”€β”€ content.js          # DOM bridge + HTML parsing
β”‚   └── icon*.png           # Extension icons (16, 48, 128)
β”‚
β”œβ”€β”€ Assets/                 # SVG icons for UI
β”‚   β”œβ”€β”€ Roth-Logo.svg
β”‚   β”œβ”€β”€ Send-Button.svg / Stop-Response.svg
β”‚   β”œβ”€β”€ Brain-lightning.svg / Brain-Icon.svg
β”‚   β”œβ”€β”€ GuardIcon.svg / SearchIcon.svg / GlobeIcon.svg
β”‚   β”œβ”€β”€ TickMarkIcon.svg / DownArrow.svg
β”‚
└── dist/                   # Build output (tinkering.js)

πŸ› οΈ Core Modules

tinkering.ts β€” Main Application

The entry point that orchestrates:

  • GPU Detection: Checks for WebGPU support and selects the best adapter.
  • Model Loading: Downloads and initializes Qwen3 (0.6B) and Halugate Sentinel classifier. Models are cached locally for faster startup.
  • UI Management: Handles chat messages, process/reasoning panels, and input events.
  • Interruptibility: AbortController allows users to stop generation mid-stream.

src/orchestrator.ts β€” Pipeline State Machine

Coordinates the multi-model workflow:

  1. Classify β†’ Uses Halugate Sentinel to determine if the query needs web search.
  2. Search β†’ If needed, fetches DuckDuckGo results via the extension.
  3. Reason β†’ Sends the query (with search context) to Qwen3 for generation.

src/streaming-parser.ts β€” Think Tag FSM

A character-by-character Finite State Machine that:

  • Detects <think>...</think> tags in LLM output.
  • Routes thinking content to the Reasoning panel.
  • Routes visible content to the main chat.

src/markdown-renderer.ts β€” Real-Time Markdown

Incrementally renders markdown as tokens stream in:

  • Uses marked for parsing and highlight.js for code blocks.
  • Buffers content to avoid rendering incomplete syntax.
  • Integrates with DOMPurify for XSS protection.

src/extension-bridge.ts β€” Extension Communication

Provides an API for the main app to:

  • Detect if the Chrome extension is installed.
  • Send search queries and receive parsed results.
  • Uses postMessage with request/response correlation.

πŸš€ Getting Started

Prerequisites

  • Bun (for building): Install Bun
  • WebGPU-capable browser: Chrome 113+, Edge 113+, or similar

Installation

# Clone the repository
git clone https://github.com/your-username/roth.git
cd roth

# Install dependencies
bun install

# Build the project
bun run build

Running Locally

Serve the project with any static file server:

# Using Bun's built-in serve (or any alternative)
bun x serve .

Then open http://localhost:3000 in your browser.


🎨 Design System

The UI uses CSS custom properties for consistent theming:

Token Value Usage
--bg-primary #171821 Main background
--bg-card #545454 Card surfaces
--accent #00a7e9 Interactive elements
--font-display Tienne Headings
--font-body Onest Body text
--neo-outset Shadow values Neomorphic raised effect
--neo-inset Shadow values Neomorphic pressed effect

πŸ“„ License

This project is provided as-is for educational and personal use.


πŸ™ Acknowledgments

About

A multi-LLM system that runs natively on your browser with search capability.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published