docs/ai-intelligence.mdx
The World Brief is generated by a 4-tier provider chain that prioritizes local compute, falls back through cloud APIs, and degrades to browser-side inference as a last resort:
┌─────────────────────────────────────────────────────────────────┐
│ Summarization Request │
│ (headlines deduplicated by Jaccard similarity > 0.6) │
└───────────────────────┬─────────────────────────────────────────┘
│
▼
┌─────────────────────────────────┐ timeout/error
│ Tier 1: Ollama / LM Studio │──────────────┐
│ Local endpoint, no cloud │ │
│ Auto-discovered model │ │
└─────────────────────────────────┘ │
▼
┌─────────────────────────────┐ timeout/error
│ Tier 2: Groq │──────────────┐
│ Llama 3.1 8B, temp 0.3 │ │
│ Fast cloud inference │ │
└─────────────────────────────┘ │
▼
┌─────────────────────────────┐ timeout/error
│ Tier 3: OpenRouter │──────────────┐
│ Multi-model fallback │ │
└─────────────────────────────┘ │
▼
┌──────────────────────────┐
│ Tier 4: Browser T5 │
│ Transformers.js (ONNX) │
│ No network required │
└──────────────────────────┘
All three API tiers (Ollama, Groq, OpenRouter) share a common handler factory (_summarize-handler.js) that provides identical behavior:
summary:v3:{mode}:{variant}:{lang}:{hash}) so the same headlines viewed by 1,000 concurrent users trigger exactly one LLM call. Cache TTL is 24 hours{fallback: true} (missing API key or endpoint unreachable), the chain silently advances to the next tier. Progress callbacks update the UI to show which provider is being attemptedThe Ollama tier communicates via the OpenAI-compatible /v1/chat/completions endpoint, making it compatible with any local inference server that implements this standard (Ollama, LM Studio, llama.cpp server, vLLM, etc.).
Clicking any country on the map opens a full-page intelligence dossier — a single-screen synthesis of all intelligence modules for that country. The brief is organized into a two-column layout:
Left column:
[1]–[8] that scroll to the corresponding news source when clickedRight column:
Headline relevance filtering: each country has an alias map (e.g., US → ["united states", "american", "washington", "pentagon", "biden", "trump"]). Headlines are filtered using a negative-match algorithm — if another country's alias appears earlier in the headline title than the target country's alias, the headline is excluded. This prevents cross-contamination (e.g., a headline about Venezuela mentioning "Washington sanctions" appearing in the US brief).
Export options: briefs are exportable as JSON (structured data with all scores, signals, and headlines), CSV (flattened tabular format), or PNG image. A print button triggers the browser's native print dialog for PDF export.
Map clicks resolve to countries using a local geometry service rather than relying on network reverse-geocoding (Nominatim). The system loads a GeoJSON file containing polygon boundaries for ~200 countries and builds an indexed spatial lookup:
[minLon, minLat, maxLon, maxLat]). Points outside the bbox are rejected without polygon intersection testing.true, and polygon holes are subtracted (a point inside an outer ring but also inside a hole is excluded).This approach provides sub-millisecond country detection entirely in the browser, with no network latency. The geometry data is preloaded at app startup and cached for the session. For countries not in the GeoJSON (rare), the system falls back to hardcoded rectangular bounding boxes, and finally to network reverse-geocoding as a last resort.
The Deduction Panel is an interactive AI geopolitical analysis tool that produces near-term timeline forecasts grounded in live intelligence data.
Request pipeline:
buildNewsContext() pulls the 15 most recent NewsItem titles from the live feed and prepends them as structured context ("Recent News:\n- Headline (Source)") — ensuring the LLM always has current situational awarenessdeductSituation RPC endpoint, which calls callLlm() with a provider fallback chain (Groq, OpenRouter, or any OpenAI-compatible endpoint via LLM_API_URL/LLM_API_KEY/LLM_MODEL env vars) with a system prompt instructing it to act as a "senior geopolitical intelligence analyst and forecaster"think tags are stripped as defense-in-depthdeduct:situation:v1:{hash(query|geoContext)} — identical queries serve instantly from cacheCross-panel integration: Any panel can dispatch a wm:deduct-context custom DOM event with { query, geoContext, autoSubmit }, which pre-fills the Deduction Panel and optionally auto-submits. This enables contextual forecasting from any part of the dashboard — clicking "Analyze" on a theater posture card can automatically trigger a regional deduction. A 5-second cooldown prevents rapid re-submission.
The panel is lazy-loaded (import()) to exclude DOMPurify from the main bundle unless the panel is actually accessed, keeping the web bundle lean.
The Headline Memory system provides browser-local Retrieval-Augmented Generation — a persistent semantic index of news headlines that runs entirely on the user's device.
Ingestion pipeline:
RSS Feed Parse → isHeadlineMemoryEnabled()? → ML Worker (Web Worker)
│
┌─────────┴──────────┐
│ ONNX Embeddings │
│ all-MiniLM-L6-v2 │
│ 384-dim float32 │
└─────────┬──────────┘
│
┌─────────┴──────────┐
│ IndexedDB Store │
│ 5,000 vector cap │
│ LRU by ingestAt │
└────────────────────┘
pooling: 'mean', normalize: true), and deduplicates by content hashingestedAt are evictedSearch: Queries are embedded using the same model, then a full cursor scan computes cosine similarity against all stored vectors. Results are ranked by score, capped at topK (1–20), and filtered by minScore (0–1). Multiple query strings can be searched simultaneously (up to 5), with the max score per record across all queries used for ranking.
Opt-in mechanism: The setting defaults to false (stored as wm-headline-memory in localStorage). Enabling it triggers mlWorker.init() → loadModel('embeddings'). Disabling it unloads the model and optionally terminates the entire worker if no other ML features are active. The ai-flow-changed CustomEvent propagates toggle changes to all interested components.
Every news item passes through a three-stage classification pipeline:
Keyword classifier (instant, source: 'keyword') — pattern-matches against ~120 threat keywords organized by severity tier (critical → high → medium → low → info) and 14 event categories (conflict, protest, disaster, diplomatic, economic, terrorism, cyber, health, environmental, military, crime, infrastructure, tech, general). Keywords use word-boundary regex matching to prevent false positives (e.g., "war" won't match "award"). Each match returns a severity level, category, and confidence score. Variant-specific keyword sets ensure the tech variant doesn't flag "sanctions" in non-geopolitical contexts.
Browser-side ML (async, source: 'ml') — Transformers.js runs NER, sentiment analysis, and topic classification directly in the browser with no server dependency. Provides a second classification opinion without any API call.
LLM classifier (batched async, source: 'llm') — headlines are collected into a batch queue and fired as parallel classifyEvent RPCs via the sebuf proto client. Each RPC calls the configured LLM provider (Groq Llama 3.1 8B at temperature 0, or Ollama for local inference). Results are cached in Redis (24h TTL) keyed by headline hash. When 500-series errors occur, the LLM classifier automatically pauses its queue to avoid wasting API quota, resuming after an exponential backoff delay. When the LLM result arrives, it overrides the keyword result only if its confidence is higher.
This hybrid approach means the UI is never blocked waiting for AI — users see keyword results instantly, with ML and LLM refinements arriving within seconds and persisting for all subsequent visitors. Each classification carries its source tag (keyword, ml, or llm) so downstream consumers can weight confidence accordingly.
The dashboard monitors five independent alert origins and fuses them into a unified breaking news stream with layered deduplication, cooldowns, and source quality gating:
| Origin | Trigger | Example |
|---|---|---|
| RSS alert | News item with isAlert: true and threat level critical/high | Reuters flash: missile strike confirmed |
| Keyword spike | Trending keyword exceeds spike threshold | "nuclear" surges across 8+ feeds in 2 hours |
| Hotspot escalation | Hotspot escalation score exceeds critical threshold | Taiwan Strait tension crosses 80/100 |
| Military surge | Theater posture assessment detects strike packaging | Tanker + AWACS + fighters co-present in MENA |
| OREF siren | Israel Home Front Command issues incoming rocket/missile alert | Rocket barrage detected in northern Israel |
Anti-noise safeguards:
threat.source !== 'keyword') to fire an alert; Tier 1–2 sources bypass this gatecritical-only (only critical severity fires) and critical-and-high (both critical and high severities)When an alert passes all gates, the system dispatches a wm:breaking-news CustomEvent on document, which the Breaking News Banner consumes to display a persistent top-of-screen notification. Optional browser Notification API popups and an audio chime are available as user settings. Clicking the banner scrolls to the RSS panel that sourced the alert and applies a 1.5-second flash highlight animation.
The dashboard runs a full ML pipeline in the browser via Transformers.js, with no server dependency for core intelligence. This is automatically disabled on mobile devices to conserve memory.
| Capability | Model | Use |
|---|---|---|
| Text embeddings | sentence-similarity | Semantic clustering of news headlines |
| Sequence classification | threat-classifier | Threat severity and category detection |
| Summarization | T5-small | Last-resort fallback when Ollama, Groq, and OpenRouter are all unavailable |
| Named Entity Recognition | NER pipeline | Country, organization, and leader extraction |
Hybrid clustering combines fast Jaccard similarity (n-gram overlap, threshold 0.4) with ML-refined semantic similarity (cosine similarity, threshold 0.78). Jaccard runs instantly on every refresh; semantic refinement runs when the ML worker is loaded and merges clusters that are textually different but semantically identical (e.g., "NATO expands missile shield" and "Alliance deploys new air defense systems").
News velocity is tracked per cluster — when multiple Tier 1–2 sources converge on the same story within a short window, the cluster is flagged as a breaking alert with sourcesPerHour as the velocity metric.
For offline resilience and reduced API costs, the system includes browser-based ML capabilities using ONNX Runtime Web.
| Model | Task | Size | Use Case |
|---|---|---|---|
| T5-small | Text summarization | ~60MB | Offline briefing generation |
| DistilBERT | Sentiment analysis | ~67MB | News tone classification |
Browser ML serves as the final fallback when cloud APIs are unavailable:
User requests summary
↓
1. Try Groq API (fast, free tier)
↓ (rate limited or error)
2. Try OpenRouter API (fallback provider)
↓ (unavailable)
3. Use Browser T5 (offline, always available)
Models are loaded on-demand to minimize initial page load:
All ML inference runs in a dedicated Web Worker:
Browser ML has constraints compared to cloud models:
| Aspect | Cloud (Llama 3.3) | Browser (T5) |
|---|---|---|
| Context window | 128K tokens | 512 tokens |
| Output quality | High | Moderate |
| Inference speed | 2-3 seconds | 5-10 seconds |
| Offline support | No | Yes |
Browser summarization is intentionally limited to 6 headlines × 80 characters to stay within model constraints.
The Insights Panel provides AI-powered analysis of the current news landscape, transforming raw headlines into actionable intelligence briefings.
Every 2 minutes (with rate limiting), the system generates a concise situation brief using a multi-provider fallback chain:
| Priority | Provider | Model | Latency | Use Case |
|---|---|---|---|---|
| 1 | Groq | Llama 3.3 70B | ~2s | Primary provider (fast inference) |
| 2 | OpenRouter | Llama 3.3 70B | ~3s | Fallback when Groq rate-limited |
| 3 | Browser | T5 (ONNX) | ~5s | Offline fallback (local ML) |
Caching Strategy: Redis server-side caching prevents redundant API calls. When the same headline set has been summarized recently, the cached result is returned immediately.
The AI receives enriched context about focal points—entities that appear in both news coverage AND map signals. This enables intelligence-grade analysis:
[INTELLIGENCE SYNTHESIS]
FOCAL POINTS (entities across news + signals):
- IRAN [CRITICAL]: 12 news mentions + 5 map signals (military_flight, protest, internet_outage)
KEY: "Iran protests continue..." | SIGNALS: military activity, outage detected
- TAIWAN [ELEVATED]: 8 news mentions + 3 map signals (military_vessel, military_flight)
KEY: "Taiwan tensions rise..." | SIGNALS: naval vessels detected
Not all news is equally important. Headlines are scored to identify the most significant stories for the briefing:
Score Boosters (high weight):
Geopolitical Multipliers:
Score Reducers (demoted):
This ensures military conflicts and humanitarian crises surface above routine business news.
Headlines are analyzed for overall sentiment distribution:
| Sentiment | Detection Method | Display |
|---|---|---|
| Negative | Crisis, conflict, death keywords | Red percentage |
| Positive | Agreement, growth, peace keywords | Green percentage |
| Neutral | Neither detected | Gray percentage |
The overall sentiment balance provides a quick read on whether the news cycle is trending toward escalation or de-escalation.
Fast-moving stories are flagged when the same topic appears in multiple recent headlines:
The Focal Point Detector is the intelligence synthesis layer that correlates news entities with map signals to identify "main characters" driving current events.
Without synthesis, intelligence streams operate in silos:
Entity Extraction: Extract countries, companies, and organizations from all news clusters using the entity registry (66 entities with aliases)
Signal Aggregation: Collect all map signals (military flights, protests, outages, vessels) and group by country
Cross-Reference: Match news entities with signal countries
Score & Rank: Calculate focal scores based on correlation strength
FocalScore = NewsScore + SignalScore + CorrelationBonus
NewsScore (0-40):
base = min(20, mentionCount × 4)
velocity = min(10, newsVelocity × 2)
confidence = avgConfidence × 10
SignalScore (0-40):
types = signalTypes.count × 10
count = min(15, signalCount × 3)
severity = highSeverityCount × 5
CorrelationBonus (0-20):
+10 if entity appears in BOTH news AND signals
+5 if news keywords match signal types (e.g., "military" + military_flight)
+5 if related entities also have signals
| Urgency | Criteria | Visual |
|---|---|---|
| Critical | Score > 70 OR 3+ signal types | Red badge |
| Elevated | Score > 50 OR 2+ signal types | Orange badge |
| Watch | Default | Yellow badge |
Focal points display icons indicating which signal types are active:
| Icon | Signal Type | Meaning |
|---|---|---|
| ✈️ | military_flight | Military aircraft detected nearby |
| ⚓ | military_vessel | Naval vessels in waters |
| 📢 | protest | Civil unrest events |
| 🌐 | internet_outage | Network disruption |
| 🚢 | ais_disruption | Shipping anomaly |
A focal point for IRAN might show:
Focal point urgency levels feed into the Country Instability Index: