Skip to content

Latest commit

 

History

28 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Nexus-SCM Pathfinder

Deterministic RAG console for supply-chain crisis response queries.

A hybrid token-efficient routing agent: answers supply-chain compliance/routing questions from a small local knowledge corpus with zero LLM tokens whenever possible, and escalates to a remote Fireworks-backed synthesis call only for recommendation/synthesis-style queries. Built as a hackathon entry for the Hybrid Token-Efficient Routing Agent track. No database, no vector store, no embeddings — routing is deterministic and fully inspectable.

Why it exists

Classic RAG routes every query through an LLM, burning tokens (and latency/cost) even when the answer is a verbatim fact sitting in a known document. This app inverts that: a tiny hard-coded supply-chain corpus (Suez surcharges, supplier SLAs, logistics risk playbooks) is scored by plain token overlap, and the LLM is called only when the query needs synthesis ("compare", "recommend") or confidence is low. The response always reports the actual route taken and the actual tokens spent (0 for local), so token efficiency is observable, not claimed.

Architecture

Browser (Next.js console)  --POST /api/query-->  FastAPI backend
                                                   │
                                                   ▼
                                           RagService.query()
                        ┌──────────────────────┼───────────────────────┐
                        │                      │                       │
                 tokenize query          score 3 corpus docs     rank top-3 citations
                        │                      │                       │
                        ▼                      ▼                       ▼
              no corpus match?          best overlap ≥ 0.5?       synthesis terms
              → local_fallback          AND no {compare,          (compare/recommend/
              (abstain, 0 tokens)       recommend, should}?       should) present?
                                               │                       │
                                               ▼                       ▼
                                         LOCAL answer            FIREWORKS synthesis
                                         (best sentence,          (once, compact prompt)
                                         0 tokens)                       │
                                                                         ▼
                                                                  fail/malformed?
                                                                  → local_fallback
                                                                  (best local snippet)

Backend (backend/, FastAPI + Pydantic v2)

  • app/main.py — app factory, CORS from CORS_ORIGINS, two endpoints:
    • GET /health{"status":"ok","mode":"local-first"}
    • POST /api/queryRagResponse
  • app/models.py — Pydantic schemas: QueryRequest (validates non-blank string query), RagResponse (answer, route, citations[≤3], trace[]), RouteDecision (target ∈ local | fireworks | local_fallback, score, fireworks_tokens, reason).
  • app/core/config.pySettings reads CORS_ORIGINS (defaults to localhost:3000/3001).
  • app/services/rag.py — the whole routing brain. Holds the corpus as string constants (not files): global_trade_sanctions_2026.md (Suez 15% war-risk tariff, Singapore HS-8542 ASEAN exemption, Cape bypass ~10-12 days), supplier_sla_contracts.md (SLA-902 Penang, SLA-504 Hamburg, SLA-233 Saigon), logistics_risk_playbook.md (route playbooks, high/critical risk thresholds). Scoring: query is tokenized ([a-z0-9]+, minus stop words); each doc gets |query ∩ doc| / |query|; the top sentence of the best doc (by sentence-level overlap) becomes the local answer.
  • app/services/fireworks.pyFireworksAgentClient: plain urllib POST to the Fireworks chat completions API (model default accounts/fireworks/models/deepseek-v4-pro, env-overridable), response_format: json_object, 25s timeout, per-process spend cap (max_cost_usd, default $5) enforced from provider usage.total_tokens at a conservative price assumption. JSON-content extraction tolerates prose wrapped around the object.

Frontend (frontend/, Next.js 14 App Router + TypeScript + Tailwind)

Single-page console (app/page.tsx): two example prompt buttons ("Singapore transit exemption", "Compare suppliers"), a query textarea, and a results panel showing the RAG answer, the routing trace (which step the query hit), the cited sources with overlap %, and the Fireworks token count for the route. lib/api.ts is a thin fetch wrapper; lib/types.ts mirrors the backend Pydantic schemas 1:1. Styling is Tailwind utility classes under BEM-ish rag-* names in globals.css.

The routing decision (exact rule)

  1. Tokenize the query, dropping stop words (a, an, and, at, are, for, is, it, of, on, or, the, this, to, what, when, with).
  2. Score all 3 corpus docs by query-term overlap ratio; keep the top 3 as citations.
  3. No overlap at alllocal_fallback: answer "I don't have enough local evidence to answer this query.", empty citations, 0 tokens, no Fireworks call.
  4. Best score ≥ 0.5 and no synthesis term (compare, recommend, should) in the query → local: answer = best-scoring sentence of the top doc, fireworks_tokens = 0.
  5. Otherwise → fireworks: one synthesis call with the top snippets and the query. Any exception or malformed response → local_fallback using the best local snippet (source-grounded, never fabricated). Reported tokens = provider usage.total_tokens; non-integer or negative values are coerced to 0.

Usage

Local backend:

cd backend
python -m pip install -e '.[test]'
python -m pytest tests -v
uvicorn app.main:app --port 8000

Local frontend:

cd frontend
npm ci
npm run dev        # http://localhost:3000

Query API:

curl --fail --header 'Content-Type: application/json' \
  --data '{"query":"What is the Suez surcharge?"}' \
  http://localhost:8000/api/query

Synthesis query (uses Fireworks only if FIREWORKS_API_KEY is set):

curl --fail --header 'Content-Type: application/json' \
  --data '{"query":"Compare suppliers and recommend one with lowest risk and cost."}' \
  http://localhost:8000/api/query

Environment

Variable Required Purpose
CORS_ORIGINS no (has default) Comma-separated frontend origins the API accepts
NEXT_PUBLIC_API_BASE_URL yes (frontend) Backend base URL for the console
FIREWORKS_API_KEY optional Enables Fireworks synthesis. Unset = local-only mode (synthesis queries fall back to local snippets)
FIREWORKS_MODEL optional Model id, default accounts/fireworks/models/deepseek-v4-pro
FIREWORKS_MAX_COST_USD optional Per-process spend cap, default 5
FIREWORKS_PRICE_USD_PER_MTOK optional Price assumption for the cap, default 1

Keep FIREWORKS_API_KEY unset for pure local behavior. Keys live only in .env (gitignored).

Docker preview

docker compose -p nexus-rag-review up --build --detach
# backend on :8000, frontend on :3000
curl --fail http://localhost:8000/health
docker compose -p nexus-rag-review down

Validation

Backend: 16 pytest tests (backend/tests/) covering the routing matrix — local fact queries use zero Fireworks calls, synthesis queries call Fireworks exactly once and report provider usage, Fireworks failure/malformed-response falls back source-grounded, no-evidence queries abstain without calling out, blank/non-string/whitespace queries rejected 422, plus tokenizer/sentence unit edges. Frontend: tsc --noEmit typecheck, next lint, next build, and a Playwright E2E (frontend/tests/nexus-flow.spec.ts) that asserts 0-token local results and mocks a Fireworks route for the synthesis example (requires live servers + browsers).

Design history

docs/superpowers/specs/2026-07-09-hybrid-rag-router-design.md documents the rework: the app began as a deterministic Suez simulator with a disconnected Gradio RAG prototype calling Groq per query; the hybrid router replaced both. Repository history (conventional commits) shows the rename path: simulator → RAG console → per-client spend tracking. A diverged, older simulation-era copy lives at /Users/arihantdeva/Documents/New project/nexus-pathfinder — do not merge from it.

Naming note

The repo is nexus-pathfinder, the Python package nexus-scm-backend, the npm package nexus-scm-frontend, the compose project nexus-rag-review — all the same app across its rename history. This is intentional; don't normalize without explicit request.

Releases

Packages

Contributors

Languages