Metadata-Version: 2.4
Name: tracescope
Version: 0.2.0a2
Summary: Embed, cluster, and visualize any text collection in 3D semantic space with learned flow fields
Author: Wiktor Tomasik
License-Expression: LicenseRef-PolyForm-Noncommercial-1.0.0
Project-URL: Homepage, https://pixedar.github.io/
Project-URL: Repository, https://github.com/Pixedar/TraceScope
Project-URL: Issues, https://github.com/Pixedar/TraceScope/issues
Keywords: llm,interpretability,embeddings,visualization,3d,semantic,clustering,flow-field,nlp,umap
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Scientific/Engineering :: Visualization
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.21
Requires-Dist: scikit-learn>=1.0
Requires-Dist: umap-learn>=0.5
Requires-Dist: metric-learn>=0.6
Requires-Dist: scipy>=1.7
Requires-Dist: ruptures>=1.1
Requires-Dist: chromadb>=0.4
Requires-Dist: openai>=1.0
Requires-Dist: httpx>=0.24
Requires-Dist: python-dotenv>=0.19
Requires-Dist: pydantic>=2.0
Requires-Dist: anthropic>=0.25
Requires-Dist: vispy>=0.12
Requires-Dist: PyOpenGL
Requires-Dist: PyQt5>=5.15
Requires-Dist: torch>=2.0
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: pytest-cov; extra == "dev"
Dynamic: license-file

# TraceScope

<p align="center">
  <img src="docs/assets/demo_v_3.gif" alt="TraceScope demo animation" width="950">
</p>

**TraceScope maps the flow of meaning**
Embed, cluster, and visualize any collection of texts in 3D semantic space — then learn a continuous semantic flow field over that space, so you can see not just where texts are, but how meaning tends to move between them.

TraceScope builds a rich semantic map from your data — with labeled axes, named clusters, trajectories, and a trained flow model that reveals how themes, intent, style, or reasoning evolve across time.

Works with **anything**: chatbot conversations, agent traces, news headlines, research papers, product reviews, diary entries, support logs, or any ordered collection of text.

Use it in two ways:
- **Interactive GUI** for visual exploration, interpretability, and presentation
- **Lightweight API** for integration into LLM agents, observability pipelines, research tools, and semantic monitoring systems

## Why TraceScope

Most embedding tools show a static cloud of points. TraceScope goes further:

- **Semantic structure** — discover clusters, labeled axes, and nearest neighbors
- **Semantic dynamics** — model trajectories and learn a continuous flow field over sparse text sequences
- **Interpretability** — inspect how a conversation, system, or dataset drifts, stabilizes, loops, or transitions
- **Integration** — use the same semantic space programmatically through a lightweight query API

## Concrete Examples

<details>
<summary><b>AI & Tech News Headlines: Where is the industry flowing?</b></summary>

~350 synthetic news headlines spanning AI, chips, climate, energy, biotech, space, and more — a synthetic test to demonstrate what TraceScope reveals. In a real deployment you'd use actual news feeds.

<p align="center">
  <img src="docs/assets/news_headlines.gif" alt="News headlines flow field with attractors" width="800">
</p>

**What TraceScope found:**
- **Axes:** *Embodiment Gradient* (abstract AI → physical robotics), *Operational Centralization* (distributed → centralized), *Autonomy Level* (human-directed → fully autonomous)
- **Clusters:** AI Compute Expansion, Warehouse Orchestration, AI Office Copilots, Real-time Production AI
- **Three global attractors** emerged — both pulling toward centralized, real-time operations, the strongest are:
  - **A1** : A centralized warehouse orchestration control plane — AI unifying visibility and execution across inventory, orders, labor, equipment, and logistics. The flow suggests industry trajectories converge toward a single AI layer coordinating embodied processes.
  - **A2**: A real-time production stabilizer — AI predicting bottlenecks, rerouting around machine failures, auto-triggering replenishment. A "plant-floor nervous system" keeping production lines stable.

Both attractors suggest the semantic flow of tech news converges toward centralized AI orchestration of physical operations — not just software intelligence, but real-world coordination.

**Note:** This uses synthetic headlines for demonstration. In practice, feed in real news data for genuine industry insights.

**Run it yourself:**
```bash
python examples/ai_news_headlines.py
```
</details>

<details>
<summary><b>PRM800K: The shape of mathematical reasoning</b></summary>

438 step-by-step math reasoning chains from [PRM800K](https://github.com/openai/prm800k) (MIT license) — a dataset of human-labeled process reward model training data. Each path is a chain of reasoning steps with per-step quality ratings. An experiment to see the overall shape and flow of mathematical reasoning in an LLM.

<p align="center">
  <img src="docs/assets/prm_demo.gif" alt="PRM800K math reasoning flow with found_error coloring" width="800">
</p>

**What TraceScope found:**
- **Axes:** *Symbolic↔Numeric* (abstract symbols vs concrete numbers), *Formulaic↔Combinatorics* (closed-form algebra vs counting/enumeration), *Notation Density* (sparse reasoning → heavy symbolic manipulation)
- **Clusters:** Triangle Centroid Geometry, Algebraic Term Manipulation, Number Pattern Solving
- **Flow + found_error coloring** revealed a continuous reasoning corridor with **four local attractors**, not just three static clusters.
- The strongest attractor (**A1**) sits in a sharply **error-associated** basin: trajectories converge toward tidy, computation-heavy numeric endgames that often terminate at the **first detected error**.
- A nearby attractor (**A4**) is strongly **success-associated**, suggesting many math failures come from **fine-grained mistakes inside otherwise very similar symbolic reasoning styles**, not from entering a completely different region of thought.
- A more distant attractor (**A2**) forms an alternate successful basin, while **A3** appears mixed — showing that outcome depends on **local flow dynamics inside a cluster family**, not cluster identity alone.

**Run it yourself:**
```bash
python examples/prm_demo.py
```
</details>

<details>
<summary><b>SWE-agent: Hidden attractors in software engineering traces</b></summary>

Running TraceScope on the [SWE-agent trajectories](https://huggingface.co/datasets/nebius/SWE-agent-trajectories) dataset (CC-BY-4.0) — real thought/action/observation cycles from an autonomous coding agent working on GitHub issues.

<p align="center">
  <img src="docs/assets/swe_agent.gif" alt="SWE-agent flow showing two attractors" width="800">
</p>

The MDN flow field discovered **two global attractors** even though the cluster distribution gave no hint of their existence. Traditional tools would show you clusters — TraceScope shows you the *currents* that pull agent behavior, computed from actual trajectory paths rather than static point distributions.

**Run it yourself:**
```bash
python examples/swe_agent.py
```
</details>


## Installation

```bash
# Full install — GPU renderer, MDN flow models, all LLM providers
pip install --pre tracescope
```

> **Note:** TraceScope is currently in alpha (`0.2.0a1`). The `--pre` flag is required to install pre-release versions. If `--pre` pulls beta versions of other packages (e.g., pydantic, ruptures), pin them to stable releases: `pip install --pre tracescope pydantic==2.12.5 ruptures==1.1.10`.

**Lighter variants** (use `--no-deps` to skip the full dependency tree):

```bash
# CPU-only — renderer + all features, no PyTorch (RBF flow still works)
# Note: all results shown in the "Concrete Examples" section were tested
# using the full GPU PyTorch version, not this CPU-only install.
pip install --no-deps --pre tracescope && pip install -r https://raw.githubusercontent.com/Pixedar/TraceScope/master/requirements-cpu.txt

# API-only — analysis pipeline, no GUI, no PyTorch
pip install --no-deps --pre tracescope && pip install -r https://raw.githubusercontent.com/Pixedar/TraceScope/master/requirements-api.txt
```

An OpenAI API key is **required** for embeddings and LLM explanations. TraceScope will not work without it. Set it in a `.env` file or pass it directly:

```env
OPENAI_API_KEY=sk-...
```

## Quick Start

### Analyze a chatbot conversation
Useful for real-world agent debugging: reveal hidden conversational attractors, looping failure modes, unstable transitions, and recovery trajectories in multi-turn chats
```python
from tracescope import TraceScopeConfig, AnalysisPipeline, auto_import

config = TraceScopeConfig(embedding_model="text-embedding-3-large")
session = auto_import("conversation.json")
pipeline = AnalysisPipeline(config)
result = pipeline.analyze(session, train_flow=True, cache_path="cache/conversation")

print(f"Axes: {result.axis_info.labels}")
print(f"Clusters: {result.cluster_labels}")
```

### Analyze any list of texts
Turn any ordered text collection into a semantic trajectory — works best with **30+ entries** for meaningful clusters and flow fields.
```python
from tracescope import TraceScopeConfig, AnalysisPipeline, from_list

config = TraceScopeConfig()


session = from_list([
    "Fed holds rates steady amid inflation concerns",
    "Tech earnings surge on AI demand",
    "Climate summit reaches carbon emissions deal",
    "Housing market cools as mortgage rates rise",
    "Quantum computing startup hits milestone",
    # ... add more entries, to get meangful flow is recommended  to have at least 30+ entries, run examples/ai_news_headlines.py for a demo with 350 synthetic news headlines
])

pipeline = AnalysisPipeline(config)
result = pipeline.analyze(session, train_flow=True, cache_path="cache/headlines")
```

> **Tip:** The MDN flow model learns best from **30+ entries** across your paths. With only 5–10 entries the flow field will be sparse. For the richest visualizations, use datasets with 50+ texts or multiple paths via `from_lists()`.

### Visualize

The included `sample_data/prm_demo_paths.json` contains 438 math reasoning chains from the PRM800K dataset — a good example of visualizing the semantic flow of step-by-step mathematical problem solving across diverse problem types.

```python
from tracescope import (
    TraceScopeConfig, AnalysisPipeline, auto_import, launch_renderer,
)

config = TraceScopeConfig(embedding_model="text-embedding-3-large")
session = auto_import("sample_data/prm_demo_paths.json")
pipeline = AnalysisPipeline(config)
result = pipeline.analyze(session, train_flow=True, cache_path="cache/prm_demo")

# Interactive 3D renderer with flow field animation
# Controls: Space=flow, B=ball, P=points, +/-=size
launch_renderer(result, explainer=pipeline.explainer)
```

## Input Formats

TraceScope accepts data in multiple formats:

### From code — single path (list of strings)

```python
from tracescope import from_list

# label is optional — useful for identifying the session in multi-session workflows
session = from_list(["text one", "text two", "text three"], label="My texts")
```

### From code — multiple independent paths

Analyze several independent sequences together with shared embeddings, clusters, and axes, but a unified MDN flow field that correctly learns from each path independently (no spurious boundary velocities):

```python
from tracescope import TraceScopeConfig, AnalysisPipeline, from_lists

config = TraceScopeConfig()
pipeline = AnalysisPipeline(config)

# labels is optional — names each path for display purposes
session = from_lists([
    ["Fed holds rates steady", "Tech earnings surge on AI", "Housing market cools"],
    ["Climate summit reaches deal", "Quantum computing milestone", "Mars rover update"],
    ["New vaccine approved", "Hospital staffing crisis", "Mental health funding"],
     # ... add more entries, to get meangful flow is recommended  to have at least 30+ entries, check examples dir with arleady prepared datasets 
], labels=["Finance", "Science", "Health"])

result = pipeline.analyze(session, train_flow=True, cache_path="cache/multi_path")
```

### From file — auto-detected format

```python
from tracescope import auto_import

session = auto_import("data.json")
```

Supported JSON formats:

**Plain string array** — simplest, works for any text collection:
```json
["First text", "Second text", "Third text"]
```

**Multi-path** — multiple independent sequences analyzed together:
```json
{
  "paths": [
    ["Path 1 text A", "Path 1 text B", "Path 1 text C"],
    ["Path 2 text A", "Path 2 text B"]
  ],
  "labels": ["First path", "Second path"]
}
```

<details>
<summary><strong>OpenAI chat format</strong></summary>

```json
{
  "model": "gpt-5",
  "messages": [
    {"role": "user", "content": "Hello"},
    {"role": "assistant", "content": "Hi there!"}
  ]
}
```
</details>

<details>
<summary><strong>Anthropic format</strong></summary>

```json
{
  "model": "claude-sonnet-4-20250514",
  "messages": [
    {"role": "user", "content": "Hello"},
    {"role": "assistant", "content": [{"type": "text", "text": "Hi!"}]}
  ]
}
```
</details>

**Plain text** (`.txt` files, split on blank lines):
```
First message

Second message

Third message
```

## Scores

Attach numeric metadata to your traces for score-based visualization. Two levels:

- **Entry scores** — per-step values (e.g., confidence at each reasoning step)
- **Path scores** — per-path aggregate values (e.g., overall success/failure)

### Adding scores via `from_lists`

```python
from tracescope import from_lists

session = from_lists(
    paths=[
        ["Step 1: search", "Step 2: found result", "Step 3: write report"],
        ["Step 1: search", "Step 2: API timeout", "Step 3: retry failed"],
    ],
    labels=["Success", "Failure"],
    entry_scores=[
        [{"confidence": 0.6}, {"confidence": 0.85}, {"confidence": 0.95}],
        [{"confidence": 0.5}, {"confidence": 0.2}, {"confidence": 0.1}],
    ],
    path_scores={
        0: {"success": 1.0},
        1: {"success": 0.0},
    },
)
```

### Adding scores via `from_list`

```python
from tracescope import from_list

session = from_list(
    ["text one", "text two", "text three"],
    entry_scores=[{"quality": 0.9}, {"quality": 0.5}, {"quality": 0.8}],
)
```

### Visualization

Score channels automatically appear in the GPU renderer sidebar:
- **Flow particle coloring** — checkbox per channel colors flow particles by interpolated score (red→yellow→green)
- **Data point coloring** — checkbox per channel colors data points by score

Score coloring is precomputed on a 3D grid for full-speed animation (no per-frame overhead).

### Programmatic access

```python
query = TraceQuery(result, pipeline.embedding_provider)

# List available score channels
lookup = query.get_lookup()
print(lookup["score_channels"])  # {"success": {"mean": 0.67, "min": 0.0, "max": 1.0}, ...}

# Score summary with per-cluster and per-path breakdown
summary = query.score_summary("success")
print(summary["cluster_breakdown"])  # [{cluster, count, mean, min, max}, ...] (mean/min/max are None when count=0)
print(summary["path_breakdown"])     # [{path_label, path_score, entry_scores_count, entry_mean}, ...] (entry_mean is None when no entry scores)
```

## Programmatic API — TraceQuery

After running the pipeline once, use `TraceQuery` for fast programmatic access to the semantic space. No re-computation needed — everything is served from the pre-computed lookup table and velocity grid.

```python
from tracescope import TraceQuery

query = TraceQuery(result, pipeline.embedding_provider, pipeline.explainer)
```

### `get_lookup()` — Space metadata

Returns a dict with all computed information about the semantic space:

```python
lookup = query.get_lookup()

lookup["axis_labels"]    # ["topic depth", "technical level", "abstraction"]
lookup["clusters"]       # [{id, label, centroid_3d, size, sample_texts}, ...]
lookup["n_points"]       # number of original data points
lookup["has_flow"]       # whether flow field is available
lookup["axis_ranges"]    # [{axis, min, max}, ...]
lookup["embedding_model"] # e.g. "text-embedding-3-large"
lookup["score_channels"] # {"success": {"mean": 0.67, ...}, ...} (if scores exist)
```

### `explain_path(texts)` — Path through semantic space

Pass a list of new texts. They get embedded and projected into the existing 3D space using the same reducer. Returns where each point lands, which clusters it's near, and an LLM-generated explanation of the overall path.

```python
result = query.explain_path([
    "What is a variable?",
    "How do classes work?",
    "Explain distributed systems",
])

result["path_3d"]       # [[x,y,z], [x,y,z], [x,y,z]]
result["points"]        # per-point: axis_percentages, cluster_distances, nearest_texts
result["explanation"]   # LLM-generated path explanation
```

### `query_flow_at(text)` — Flow field snapshot

Embeds a single text and queries the flow field at that position. Returns the velocity vector decomposed into:
- **Axis components**: how strongly you're being pulled along each semantic axis
- **Cluster pull**: toward/away from each cluster with alignment score
- **Nearby points**: closest original texts and whether the flow would carry you through them

```python
result = query.query_flow_at("How do I deploy to production?")

result["velocity"]             # [vx, vy, vz]
result["speed"]                # magnitude
result["axis_decomposition"]   # [{axis_label, component, magnitude, direction}, ...]
result["cluster_pull"]         # [{cluster_label, alignment, distance, interpretation}, ...]
result["nearby_points"]        # [{text, distance, velocity_alignment, would_pass_through}, ...]
```

### `query_direction_at(texts)` — Direction estimate without flow field

Like `query_flow_at` but estimates direction from the path itself (no MDN needed). Pass 2+ texts — direction is computed from consecutive differences.

```python
result = query.query_direction_at([
    "What is Python?",
    "How do I use async/await?",
    "Building production microservices",
])

result["estimated_direction"]   # [dx, dy, dz]
result["estimated_magnitude"]   # float
result["axis_decomposition"]    # same format as query_flow_at
result["cluster_pull"]          # same format as query_flow_at
```

### `path_similarity(path_a, path_b)` — Compare semantic paths

Compares two text sequences using high-dimensional embeddings (no 3D projection). Uses Frechet distance (order-aware), DTW-aligned cosine similarity, and direction alignment.

```python
result = query.path_similarity(
    ["How to read files", "How to write files", "How to delete files"],
    ["How to open DB", "How to query tables", "How to close connections"],
)

result["overall_score"]          # 0-1, higher = more similar
result["direction_similarity"]   # are the paths going in the same direction?
result["frechet_distance"]       # order-aware distance (lower = closer)
result["mean_cosine_similarity"] # average point-to-point similarity
result["start_similarity"]       # how similar are the starting points
result["end_similarity"]         # how similar are the ending points
```

## Visualization

### Interactive 3D Renderer (`launch_renderer`)

All-in-one interactive 3D viewer with particle flow animation, probe controls, and LLM explanations. Uses GPU acceleration by default, falls back to software rendering automatically when no GPU is available.

```python
from tracescope import launch_renderer

# Basic — no LLM explain
launch_renderer(result)

# With LLM explanations (pass the pipeline's explainer)
launch_renderer(result, explainer=pipeline.explainer)
```

**GUI panels** (left sidebar):
- **Flow Controls** — flow animation and ball/probe toggle
- **Display** — data points, path visibility, spline path toggle, info overlay
- **Probe** — X/Y/Z sliders, mark/clear control points, Explain button
- **Clusters** — color-coded legend with cluster descriptions
- **Flow Settings** — particle opacity, speed multiplier, particle count slider, entropy coloring

**Double-click** on a data point in the 3D view to see its text, cluster, and metadata.

## Configuration

```python
from tracescope import TraceScopeConfig

config = TraceScopeConfig(
    openai_api_key="sk-...",          # or set OPENAI_API_KEY env var
    anthropic_api_key="sk-ant-...",   # optional, for Anthropic LLM provider
    embedding_model="text-embedding-3-large",  # or "text-embedding-3-small"
    embedding_provider_type="openai",
    llm_model="gpt-5-mini",          # for axis/cluster labeling
    llm_model_complex="gpt-5",       # for explanations (explain button, path explain)
    llm_provider_type="openai",      # or "anthropic"
    storage_dir="~/.tracescope",     # where embeddings and caches are stored
    cache_enabled=True,              # cache LLM responses and ML results

    # Flow model settings
    flow_mode="mdn",                 # "mdn" (default) or "rbf"
    mdn_hidden=100,                  # MDN hidden layer size (50-300)
    mdn_iters=8000,                  # MDN training iterations (2000-20000)
    velocity_grid_size=40,           # 3D velocity grid resolution (20-60)
    param_range=[5, 10, ..., 195],   # By default, UMAP searches the full range from 5 to 195 in steps of 5 which is slow; for much faster runs, you can provide only one or two values to search, but this will usually reduce quality
    rbf_kernel="thin_plate_spline",  # RBF kernel (see below)
    rbf_smoothing=0.1,               # RBF regularization (0 = exact)
)
```

> **Model override:** For the highest quality labels and explanations, set both models to `gpt-5`:
> ```python
> config = TraceScopeConfig(llm_model="gpt-5", llm_model_complex="gpt-5")
> ```
> You can use any OpenAI chat model — just pass its name to `llm_model` / `llm_model_complex`.

### Flow Models

TraceScope supports two flow field models for learning velocity fields from your semantic trajectories:

**MDN (Mixture Density Network)** — Default. A 2-component neural network that learns a probabilistic velocity field. Best for complex, multi-modal flow patterns. Requires PyTorch.

```python
result = pipeline.analyze(session,
    flow_mode="mdn",
    mdn_hidden=150,     # larger = more expressive (default 100)
    mdn_iters=12000,    # more iterations = more refined (default 8000)
    velocity_grid_size=50,  # higher res grid (default 40)
)
```

**RBF (Radial Basis Function)** — Lightweight alternative using scipy's `RBFInterpolator`. Produces smoother, more conservative flows. No PyTorch required — uses only scipy.

```python
result = pipeline.analyze(session,
    flow_mode="rbf",
    rbf_kernel="thin_plate_spline",  # or "cubic", "linear", "quintic"
    rbf_smoothing=0.1,               # 0 = exact interpolation, higher = smoother
)
```

Both models produce compatible velocity grids and work identically in the visualizer and `TraceQuery` API.

### Result Caching

Save and reload full pipeline results to skip re-computation:

```python
# First run — computes everything and saves
result = pipeline.analyze(session, cache_path="results/my_analysis")

# Second run — loads instantly if texts and embedding model match
result = pipeline.analyze(session, cache_path="results/my_analysis")

# Manual save/load (parent directories are created automatically)
result.save_result("results/my_analysis")
loaded = AnalysisResult.load_result("results/my_analysis")
```

The cache uses a SHA-256 fingerprint of sorted texts + embedding model name. If your data changes, the cache is automatically invalidated and the pipeline re-runs.

## Pipeline Steps

The `analyze()` method runs these steps:

1. **Embed** — Convert texts to high-dimensional vectors (OpenAI text-embedding-3-large, 3072D)
2. **Cluster** — Auto-select k via silhouette scoring, KMeans with k-means++ (configurable `min_k`, default 3)
3. **Reduce to 3D** — UMAP/tSNE grid search with cosine metric, pick best silhouette
4. **Compute axes** — PCA on projected coordinates
5. **Label axes** — LLM generates 2-word semantic labels using TF-IDF keyword evolution
6. **Label clusters** — LLM generates cluster descriptions with avoid mechanism + keyword differentiation
7. **Train flow model** — MDN (mixture density network) or RBF (radial basis function) learns velocity field from the trajectory
8. **Build velocity grid** — configurable grid (default 40³) of pre-computed velocities for fast trilinear interpolation

## Project Structure

```
tracescope/
  analysis/       # Pipeline, clustering, dim reduction, MDN, explainer
  models/         # TraceEntry, TraceSession, AnalysisResult, AxisInfo
  providers/      # Embedding (OpenAI) and LLM (OpenAI/Anthropic) providers
  storage/        # ChromaDB vector store + SQLite cache
  visualization/  # 3D renderer (vispy), flow field system, probe
  query.py        # TraceQuery programmatic API
  config.py       # TraceScopeConfig
  prompts.py      # All LLM prompt templates
```
