Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ jobs:
- run: go test -short -race -count=1 ./cmd/... ./internal/...
- run: go vet ./cmd/... ./internal/...
- run: go build ./cmd/api
- run: make wasm-check

dashboard:
runs-on: ubuntu-latest
Expand All @@ -38,6 +39,13 @@ jobs:
- run: npm run lint
- run: npm test
- run: npm run build
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- name: Build the in-browser runtime (WASM core)
working-directory: .
run: make wasm-build
- run: npx playwright install --with-deps chromium
- run: npm run e2e

Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,7 @@ __pycache__/

# Local dynamic-int8 reranker export produced by sidecars/reranker/quantize.py
int8_avx2/

# Built by `make wasm-build` for the in-browser runtime
web/dashboard/public/nadir/
web/dashboard/.wrangler/
27 changes: 27 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,33 @@ The React dashboard remains in `web/dashboard`, and the Python reranker and
optional Docling processes remain in `sidecars/`. Compose builds `cmd/api`, so
normal local and Compose startup use the same backend.

## Browser runtime (WASM)

`cmd/wasm` builds the same graph for the browser (ADR 0038): `make wasm-build`
writes `.local/wasm/` and `web/dashboard/public/nadir/`; `make wasm-check`
builds, vets and tests it under wasm plus a Node smoke test of the whole API.
Select it in the dashboard with `?runtime=browser` (`&models=mock` for scripted
models, `&llm=none` for retrieval only) or `VITE_RUNTIME=browser`. Keep
`internal/bootstrap/assembly` and `internal/core/**` free of gRPC, OS and
server-only imports so they stay buildable for js/wasm.

Testing the browser runtime (`make` targets from the repo root, `npm`/`npx` from
`web/dashboard`):

| Layer | Command | Needs |
|-------|---------|-------|
| Go + wasm + Node API smoke test | `make wasm-check` | Go, node |
| Store benchmark (exact vs HNSW) | `go test -run '^$' -bench HybridSearch -benchtime=100x ./internal/providers/memory/documents` | about 5 min; builds up to 50k chunks |
| Dashboard unit tests | `npm test` | node |
| Browser e2e, scripted models | `make wasm-build`, then `npx playwright test e2e/browser-runtime.spec.ts` | Chrome; no downloads or GPU |
| Real embedder + reranker | `E2E_REAL_MODELS=1 npx playwright test e2e/browser-runtime-real.spec.ts` | ~330 MB download, cached in `.local/pw-real-models-profile` |
| Real WebLLM answer | `E2E_REAL_LLM=1 npx playwright test e2e/browser-runtime-llm.spec.ts` | WebGPU and a ~1.2 GB download; set `E2E_LLM_MODEL` to change the model |

Try it by hand: `make wasm-build`, then `npm run dev` and open
`/?runtime=browser` (add `&models=mock` to skip downloads). Headless Chrome on
Linux needs the Vulkan flags the LLM spec sets to see a GPU, and drivers without
WebGPU `shader-f16` need a `q4f32_1` model id (default builds are `q4f16_1`).

## Key rules

- Core use cases must not import `internal/edge/http/`, `internal/providers/`,
Expand Down
24 changes: 23 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: run compose compose-rerank test race vet build benchmark benchmark-ui eval eval-generate help check mdn generate-mocks
.PHONY: run compose compose-rerank test race vet build wasm-build wasm-smoke wasm-check benchmark benchmark-ui eval eval-generate help check mdn generate-mocks

GO_PACKAGES := ./cmd/... ./internal/...
MOCKERY_VERSION ?= v2.53.7
Expand Down Expand Up @@ -26,6 +26,28 @@ vet:
build:
go build ./cmd/api

WASM_DIR := .local/wasm

# Browser runtime: cmd/wasm assembles the retrieval and indexing graph over
# in-memory storage and host-supplied model functions.
wasm-build:
mkdir -p $(WASM_DIR)
GOOS=js GOARCH=wasm go build -o $(WASM_DIR)/nadir.wasm ./cmd/wasm
cp "$$(go env GOROOT)/lib/wasm/wasm_exec.js" $(WASM_DIR)/wasm_exec.js
mkdir -p web/dashboard/public/nadir
cp $(WASM_DIR)/nadir.wasm $(WASM_DIR)/wasm_exec.js web/dashboard/public/nadir/

# End-to-end Node smoke test of the built wasm (ingest, query, snapshot, reset).
wasm-smoke: wasm-build
node cmd/wasm/smoke.mjs $(WASM_DIR)/wasm_exec.js $(WASM_DIR)/nadir.wasm

# Keeps the provider-independent graph buildable and runnable as WASM (needs
# node). The assembly test drives ingest, chunking, embedding, storage and
# search through in-memory providers inside the wasm runtime.
wasm-check: wasm-smoke
GOOS=js GOARCH=wasm go vet ./internal/core/... ./internal/bootstrap/assembly ./internal/providers/browser ./internal/providers/memory/... ./cmd/wasm
GOOS=js GOARCH=wasm go test -count=1 -exec="$$(go env GOROOT)/lib/wasm/go_js_wasm_exec" ./internal/bootstrap/assembly ./internal/providers/memory/...

benchmark:
$(BENCHMARK_PYTHON) -m benchmark $(ARGS)

Expand Down
Loading
Loading