Loading model catalogue…

Research Query

0 tokens
πŸ–ΌοΈ Drop an image here, paste from clipboard (⌘V / Ctrl-V), or choose file
Vision-capable models will see it; text-only models will ignore it.
attached
Running...
Select Models
⚑ Pre-flight Analysis
Intent
β€”
Complexity
β€”
Input Tokens
β€”
✨ Optimised Prompt (edit before running)
Est. Cost

πŸ“‹ Session History

🧠 Memory Context

Injected into every query as background context.

πŸ”§ Technical Reference

How the Research Lab works under the hood. Updated as the system evolves.

Architecture

Single Cloudflare Pages project. Static dashboard + a Pages Function (Workers runtime) for the API. No external state.

Browser
   β”‚
   β”‚  GET  /                  β†’ static index.html (this page)
   β”‚  POST /api/research-lab  β†’ Pages Function β†’ OpenRouter
   β–Ό
Cloudflare Pages: research-lab
   β”œβ”€β”€ index.html
   β”œβ”€β”€ _headers
   └── functions/api/research-lab.ts
Public URLresearch-lab-9u3.pages.dev
Custom domainresearch.accs.website (once CNAME lands)
API endpoint/api/research-lab (same origin β€” no CORS)
AuthNone. Secret OPENROUTER_API_KEY stays on the server.
RuntimeCloudflare Workers (V8 isolates) β€” not Node, not Deno.

Request flow: prompt β†’ output

  1. Type query β€” token counter (chars/4) live; buttons unlock at β‰₯5 chars + model catalogue loaded.
  2. Click ⚑ Analyse β€” runs rule-based preflight in the browser. Zero network. Result populates Intent Β· Complexity Β· Tokens Β· Optimised Prompt Β· per-model cost chips.
  3. Edit optimised prompt (optional) β€” overrides the raw query on Run.
  4. Click β–Ά Run β€” POST to /api/research-lab with selected models + memory context.
  5. Pages Function fans out β€” Promise.allSettled hits OpenRouter once per model in parallel. Failures isolated.
  6. Per-model parsing β€” regex captures Step N: lines; split on ## Final Answer; cost computed from local pricing table Γ— provider's token counts.
  7. Response renders β€” model cards with collapsible Steps + Chain of Thought, final answer, token counts, per-card cost.
  8. Session pushed to localStorage['rl_h'] (FIFO, cap 50). Click in History to replay.

latencyEdge round-trip ~10 ms. Run dominated by slowest model in the fan-out (typically 5–30 s).

Rule-based preflight heuristics

The ⚑ Analyse path is 100% browser-side. No LLM call, no cost, instant.

Intent β€” first matching keyword group wins, in this order. All matches are whole-word, case-insensitive (regex word boundaries) so derivation doesn't trigger derive.

IntentTrigger words / phrases
mathematicalderive, calculate, prove, equation, theorem, solve for, integral, optimization, differentiate, integrate, gradient, formula, probability of, expected value, matrix, eigenvalue
comparative_analysiscompare, vs, versus, difference between, tradeoff, trade-off, pros and cons, rank, better than, contrast, side by side, head to head
literature_reviewliterature, papers on, studies on, research on, cite, publications, survey of, review of, meta-analysis, systematic review, peer-reviewed, recent work
experimental_designexperiment, study design, protocol, control group, ablation, a/b test, methodology, hypothesis, placebo, double blind, sample size, treatment group, controlled trial
technical_deep_diveimplement, build a, code for, design a, architecture, algorithm, how does, function that, write a script, engineer, framework, pipeline, refactor, develop a, construct a, optimise/optimize the
factual_lookupwhat is, who is, when did, where is, define, meaning of, definition of, describe, tell me about
exploratory(fallback β€” nothing matched)

Complexity score (1–10) β€” additive heuristics:

  • Base: +2
  • Word count >30 / >60 / >120 β†’ +1 each tier (max +3)
  • Multiple question marks β†’ +1
  • Contains acronym (3+ caps) β†’ +1
  • Contains numeric with unit (e.g. 15kg, 5%) β†’ +1
  • Contains code block, =>, function, or class β†’ +2
  • Intent in {mathematical, technical_deep_dive, experimental_design} β†’ +1
  • Intent is factual_lookup β†’ -2 (with floor of 1)

Score maps to: ≀3 simple4–6 mediumβ‰₯7 hard

Model suggestions by complexity:

  • simple β†’ gpt-oss-120b:free
  • medium β†’ gpt-oss-120b:free, gemma-4-31b-it:free
  • hard β†’ gemma-4-31b-it:free, gpt-oss-120b:free, nemotron-nano-12b-v2-vl:free

Model catalogue

All three models are on OpenRouter's :free tier β€” $0 per query. Subject to free-tier rate limits.

ModelProviderVisionTier
GPT OSS 120BOpenAIβ€”free
Nemotron Nano 12B VLNVIDIAimage, videofree
Gemma 4 31BGoogleimage, videofree

Attached images are routed to vision-capable models as image_url content blocks; text-only models receive the prompt unchanged.

API endpoints

GET /api/research-lab β€” health check, returns service metadata.

POST /api/research-lab with one of two actions:

// list available models + pricing
{ "action": "list_models" }

// fan out a query to N models in parallel
{
  "action": "run",
  "query": "...",
  "models": ["openai/gpt-oss-120b:free", "nvidia/nemotron-nano-12b-v2-vl:free"],
  "sessionContext": "optional memory blob",
  "image": "data:image/jpeg;base64,..."   // optional; only sent to vision-capable models
}

Response shape for run:

{
  "outputs": [
    {
      "modelId": "...",
      "modelName": "...",
      "provider": "...",
      "answer": "...",
      "reasoning": "...|null",
      "steps": ["Step 1: ...", ...],
      "sawImage": true,
      "inputTokens": 0,
      "outputTokens": 0,
      "cost": 0,
      "error": false
    },
    ...
  ],
  "totalCost": 0,
  "query": "..."
}

State + persistence

localStorage['rl_h']Session history β€” up to 50 most recent queries with full outputs. JSON array.
localStorage['rl_m']Memory context β€” free-text. Sent as sessionContext on every Run.
Server-sideNothing. Pages Function is stateless. Queries are not logged.

Persistence is per-browser-per-device. Clearing site data wipes history + memory. There is currently no cross-device sync.

Cost model

ComponentFree tierSteady cost
Cloudflare Pages requests + bandwidthUnlimited static$0
Cloudflare Pages Functions invocations100,000 / day$0
Preflight (rule-based)β€”$0
OpenRouter (all 3 models on :free)rate-limited free$0
Domain accs.websiteowned$0

Infra + per-query cost: $0/mo. Free-tier rate limits apply at OpenRouter (currently ~20 req/min and a daily cap; check the OpenRouter dashboard for current values).

Limits + known gotchas

  • Token counter is char/4 β€” approximate. Provider's usage.prompt_tokens is authoritative and shown post-Run.
  • 4096 max output tokens per model call (set in API). Long answers may be truncated.
  • No retry on provider error β€” failed models return inline error cards. Re-Run to retry that model.
  • Free-tier rate limits β€” OpenRouter throttles :free models per-minute and per-day. Heavy use will see 429 errors that surface as inline error cards.
  • Image size β€” dropped/pasted/uploaded images are base64'd inline in the request body. Stay under ~5 MB to avoid hitting OpenRouter request-size caps.
  • Vision routing β€” when an image is attached, it's only sent to vision-capable models (Nemotron, Gemma). Text-only models still receive the prompt.
  • History capped at 50 β€” oldest entries fall off automatically.

Migration history

  • Origin β€” Base44 monolithic Deno function at scientist-1-d28c6e14.base44.app/functions/researchLab.
  • Migrated to Cloudflare Pages + Pages Functions, single-account, no Supabase needed.
  • Removed dead import @base44/sdk + body.apiKey footgun before porting.
  • LLM preflight stripped β€” replaced with deterministic browser rules.