Live 3D vector-field visualizer + agentic answering + retrieval/SKG improvements#2
Merged
Conversation
…ong edges Raw z-scores explode on large corpora (strong edges reach z=50-100+), so the prior tanh(z/3) saturated every real association at +1.0 and discarded all gradation. Log-compress first — sign(z)*ln(1+|z|) — then bound with tanh, so a z of 10 and a z of 100 stay distinguishable while the score still passes through 0 at independence and goes negative for avoidance. On the Monte Cristo graph, edges now spread from +0.78 (Noirtier–Valentine) down through the mid-range to meaningful negatives (Monte Cristo–Villefort = -0.48: adversaries who co-occur below chance, which Jaccard naively rates +0.12). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
release.yml: on a pushed `v*` tag (or manual dispatch against a tag), builds optimized `lume` binaries for all major platforms and attaches them, with SHA-256 sums, to the GitHub Release: - x86_64-unknown-linux-gnu - aarch64-unknown-linux-gnu (cross-linked) - x86_64-apple-darwin (Intel macOS) - aarch64-apple-darwin (Apple Silicon) - x86_64-pc-windows-msvc ci.yml: build + test on ubuntu/macos/windows for every push and PR to main. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The thing static embedding layouts (UMAP/t-SNE) throw away: the *acceleration* of vectors toward each other. This streams Lume's phase-binding + Weber search relaxation and renders it live in 3D. Rust (src/stream.rs, `lume stream <query>`): - Retrieves the query's top-K candidates (BM25 + SKG), embeds them via shivvr (read-only), fits a fixed top-3 PCA frame, and runs a Kuramoto-phase × Weber × in-phase-vector-warp relaxation (mirrors the psyche/gte_weber_teacher dynamics). - Emits one NDJSON frame per step on stdout: per node — 3D pos, velocity, acceleration, phase, cluster, cosine-to-query, and approach-velocity/ acceleration toward the query (d̈ of cosine distance). Diagnostics on stderr so stdout stays a clean frame channel. No new Rust deps (std + serde_json). Front-end (viz/): - server.js — Node WebSocket bridge: spawns `lume stream`, relays NDJSON frames to the browser, serves the built app. - React + three.js (@react-three/fiber) — candidates as a force field; sphere size/glow = cosine-to-query; green/red arrows = accelerating toward/away from the query; colors = emergent phase clusters; Kuramoto coherence (R) meter; scrub/play/speed playback with frame interpolation. Verified end-to-end headless: `lume stream` emits correct frames (candidates for "Dantès escapes the prison and finds the treasure" resolve to Chapter 18 "The Treasure"; phase coherence climbs as assemblies bind), the React app builds, and a WebSocket client drives the bridge through a full meta→frames→done relay. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Feedback from running it live: - Nodes labeled with the retrieval **weight** (BM25+SKG score) instead of the long passage title — far less clutter. Full passage text now appears on **hover** (tooltip shows weight, cosine-to-query, and live approach d̈). - **Declutter**: near-identical candidate vectors (adjacent parts of the same chapter projected to nearly the same point) were stacking. Added a constant per-section display jitter (kinematics still use the true projection, so velocity/acceleration are unaffected) and widened the PCA spread. - **Ctrl-drag pans** the camera (left=rotate normally; hold Ctrl to pan); right-drag also pans, scroll zooms. Smaller spheres so arrows read clearly. stream.rs now forwards `score` + a longer `text` excerpt in the meta frame and applies the jitter to the emitted position only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Addresses live-viewing feedback: - **Full-spectrum colors**: each result gets a distinct hue ordered by cosine-to- query (warm = most related), so relevance-neighbours sit next to each other on the rainbow instead of everything collapsing to one cluster color. Arrows and labels take the node's hue. - **Warped orbs**: each sphere is stretched into an ellipsoid along its velocity (with an acceleration pulse), so a vector being strongly warped through the space visibly elongates toward where it's heading. New "orb warp" slider. - **Varying sizes**: candidate radius scales with retrieval weight; the query orb is shrunk so it no longer dominates. - **Physics separation**: a position-based collision-resolution pass pushes any overlapping orbs apart along their centre line (12 iterations, query immovable) so results never intersect and are all visible. - **Shading**: meshPhysicalMaterial (clearcoat) under a key + fill directional light, so the warped orbs read as solid 3D. Dropped the CDN Environment HDR to keep it offline-safe. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…query - **Results cluster around the query**: candidates now orbit their anchor query on a fixed ray at a radius that shrinks with cosine-similarity, so nearest = most relevant and binding visibly pulls them inward (acc arrows read as true approach). Was previously raw PCA position, which didn't track relevance. - **Additive search**: `lume stream <q> --add <q2> …` runs one relaxation over the union of all queries' top-K in a shared PCA frame. `Add` button (Ctrl- Enter) unions a new query into the live field; each query is its own coloured anchor with a halo. - **Overlap detection**: candidates retrieved by 2+ queries carry `members` and render gold with a halo — you can see which results the searches share. - **Halos** on query orbs (and overlaps) via an additive radial sprite. - **Smaller labels**; query/overlap colours matched to side-panel chips. Rust: stream::run takes `&[String]` queries + `&[Candidate]` (with member sets); handle_stream unions per-query BM25+SKG hits and records overlap membership. Verified end-to-end through the bridge: 2 queries → 15 union candidates → 9 overlaps flagged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- **Results panel** (right): scrollable list of every result with its colour dot, weight, label, relevance bar, and approach indicator. Re-sorts live by the values shown — relevance / weight / binding / overlap. Hovering a row highlights its orb (and vice-versa) via shared hover state. - **Delete a query**: each search chip has an × that removes it and reruns over the remaining queries. - **Cluster spread** slider: scales each cluster outward from its query so you can pull overlapping groups apart for viewing. - **Colours vary by search**: per-query hue families (matched to the chips); a single search keeps the full-relevance spectrum; overlaps stay gold. - **No-overlap**: separation pass strengthened — 26 iterations, padded collision radius (covers the warp ellipsoids), early-out on convergence. - Shared colour logic factored into colors.js so the list and orbs always agree. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
VectorField's node map still referenced the removed internal setHovered. Route hover through the controlled onHover prop, adapting the Node's (node|null) signal to the parent's id-based setter. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
You can now ask a question and see the answer AND the exact nodes behind it.
Rust (src/answer.rs, `lume answer <question>`):
- Agentic loop over a local Ollama model (default gpt-4o-mini): plan search
queries → retrieve + animate the field → evaluate sufficiency → refine queries
(lume_not_found-style, up to --rounds) → synthesize a cited answer.
- Streams NDJSON events through the same bridge: question, plan (per round),
evaluate, the relaxation frames, and answer {text, used:[node ids],
cites:[node ids]}. Citations map [n] markers back to specific orbs.
- Reuses the agent.rs Ollama pattern; retrieve_union factored out and shared
with `lume stream`. stream::run gains an emit_done flag for multi-round use.
Viz:
- "Ask" button runs the agentic loop; answer panel shows the question, the
per-round plan/evaluate log, the answer text, and clickable source chips that
highlight their orb. Cited nodes glow (icy blue), "considered" nodes get a soft
halo. Query orbs are now translucent.
Verified end-to-end through the bridge: "How did Dantès escape the Château d'If?"
→ 3 plan rounds (3→5→6 queries) → cited answer mapping to nodes [27,13,7].
answer.rs unit tests for JSON-span extraction + citation parsing pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
answer agent: diversify the planner/evaluator queries so event-phrased passages (e.g. a death described as "died of starvation", not "death") actually surface instead of anchoring on the question's proper nouns; scale n_feed with -k so raising candidates feeds the model more; set num_ctx=16384 and widen snippets to 180 words so multi-passage prompts aren't silently truncated. Fixes the "provided passages do not contain" false-negative on questions whose answer uses different vocabulary. viz: orbs warp in from hyperspace on each new field — each orb is flung out along its radial line, stretched into a thin streak, and eased back with easeOutExpo in a staggered cascade, driven by a per-orb useFrame so it plays even before relaxation frames finish streaming. .gitignore: ignore .env (holds NUTS_SERVICES_TOKEN). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Three posts in docs/blog/: - how-lume-works-part1-primitives.md — Part 1: retrieval primitives (field-aware BM25, two-stage roaring/Gödel pruning, local GTR-T5 vectors, significance-scored entity graph, the blend, tuning knobs), with the retrieval-bug case study. - hyperspace-search-deep-dive.md — Part 2: the visualization (PCA + Weber/Kuramoto relaxation, NDJSON over the WebSocket bridge, the Three.js warp-in renderer). - hyperspace-search.md — narrative story post. Annealed for accuracy against source; code refs are plain path:line, inter-post links relative. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
LICENSE file (copyright DeepBlue Dynamics) and license = "BSD-3-Clause" in Cargo.toml. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Brings the live 3D vector-field visualizer and agentic answering to Lume, plus retrieval-quality improvements, a documentation series, and licensing.
What's included
Visualizer (
lume stream+viz/)Agentic answering (
lume answer+ Ask mode)n_feedwith-k; setnum_ctxand widen snippets so multi-passage prompts aren't truncated. Fixes the "provided passages do not contain" false-negative.Retrieval core
Docs
docs/blog/— "How Lume Works" Part 1 (retrieval primitives) & Part 2 (the visualization), plus a narrative post. Fact-checked against source.Licensing / CI
LICENSE+licensefield inCargo.toml.Notes
.env(holdsNUTS_SERVICES_TOKEN) is gitignored and not committed.LICENSEis "DeepBlue Dynamics" — easy to change if a different entity is preferred.🤖 Generated with Claude Code