Skip to main content

Intelligent LLM model router driven by real code metrics โ€” successor to preLLM

Project description

img.png

llx

Intelligent LLM model router driven by real code metrics.

PyPI License: Apache-2.0 Python

AI Cost Tracking

PyPI Version Python License AI Cost Human Time Model

  • ๐Ÿค– LLM usage: $6.1500 (41 commits)
  • ๐Ÿ‘ค Human dev: ~$1192 (11.9h @ $100/h, 30min dedup)

Generated on 2026-03-29 using openrouter/qwen/qwen3-coder-next


Successor to preLLM โ€” rebuilt with modular architecture, no god modules, and metric-driven routing.

llx analyzes your codebase with code2llm, redup, and vallm, then selects the optimal LLM model based on actual project metrics โ€” file count, complexity, coupling, duplication โ€” not abstract scores.

Principle: larger + more coupled + more complex โ†’ stronger (and more expensive) model.

Why llx? (Lessons from preLLM)

preLLM proved the concept but had architectural issues that llx resolves:

Problem in preLLM llx Solution
cli.py: 999 lines, CC=30 (main), CC=27 (query) CLI split into app.py + formatters.py, max CC โ‰ค 8
core.py: 893 lines god module Config, analysis, routing in separate modules (โ‰ค250L each)
trace.py: 509 lines, CC=28 (to_stdout) Output formatting as dedicated functions
Hardcoded model selection Metric-driven thresholds from code2llm .toon data
No duplication/validation awareness Integrates redup + vallm for richer metrics

Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    IDE / Agent Layer                        โ”‚
โ”‚  Roo Code โ”‚ Cline โ”‚ Continue.dev โ”‚ Aider โ”‚ Claude Code      โ”‚
โ”‚  (point at localhost:4000 as OpenAI-compatible API)         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                  โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚              LiteLLM Proxy (localhost:4000)                 โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”     โ”‚
โ”‚  โ”‚ Router   โ”‚  โ”‚ Semantic     โ”‚  โ”‚ Cost Tracking      โ”‚     โ”‚
โ”‚  โ”‚ (metrics)โ”‚  โ”‚ Cache (Redis)โ”‚  โ”‚ + Budget Limits    โ”‚     โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
        โ”‚
   โ”Œโ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
   โ”‚    โ”‚           Model Tiers                   โ”‚
   โ”‚    โ”œโ”€โ”€ premium:  Claude Opus 4               โ”‚
   โ”‚    โ”œโ”€โ”€ balanced: Claude Sonnet 4 / GPT-5     โ”‚
   โ”‚    โ”œโ”€โ”€ cheap:    Claude Haiku 4.5            โ”‚
   โ”‚    โ”œโ”€โ”€ free:     Gemini 2.5 Pro              โ”‚
   โ”‚    โ”œโ”€โ”€ openrouter: 300+ models (fallback)    โ”‚
   โ”‚    โ””โ”€โ”€ local:    Ollama (Qwen2.5-Coder)      โ”‚
   โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
        โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚            Code Analysis Pipeline                           โ”‚
โ”‚  code2llm โ†’ redup โ†’ vallm โ†’ llx                             โ”‚
โ”‚  (metrics โ†’ duplication โ†’ validation โ†’ model selection)     โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

MCP Server Integration (NEW)

llx now provides a complete MCP (Model Context Protocol) server that exposes all wronai tools as MCP endpoints:

By default, the MCP server runs over stdio for Claude Desktop. If you need to connect from a web client or another process, start the SSE server explicitly and use the /sse and /messages/ endpoints.

# Start MCP server for Claude Desktop (stdio)
llx mcp start

# Start MCP server over SSE for web/remote clients
llx mcp start --mode sse --port 8000

# SSE endpoint: http://localhost:8000/sse
# Message endpoint: http://localhost:8000/messages/

# Generate Claude Desktop config
llx mcp config

# List available MCP tools
llx mcp tools

SSE / HTTP clients

For clients like pyqual that expect an HTTP SSE endpoint, start llx in SSE mode:

llx mcp start --mode sse --port 8000
# or
python -m llx.mcp --sse --port 8000

Then point the client at:

http://localhost:8000/sse

MCP Tools Available

Tool Description Wraps
llx_analyze Analyze project and recommend model llx analyze
llx_select Quick model selection llx select
llx_chat Analyze + select model + send prompt llx chat
code2llm_analyze Run code2llm static analysis code2llm CLI
redup_scan Run duplication detection redup CLI
vallm_validate Validate code quality vallm API/CLI
llx_proxy_status Check LiteLLM proxy status llx proxy status
llx_privacy_scan Scan text for sensitive data -
llx_project_anonymize Anonymize entire project -
llx_project_deanonymize Deanonymize LLM responses -
aider AI pair programming tool aider CLI

Claude Desktop Setup

{
  "mcpServers": {
    "llx": {
      "command": "python3",
      "args": ["-m", "llx.mcp.server"]
    }
  }
}

Installation

pip install llx

# With integrations
pip install llx[all]        # Everything + MCP
pip install llx[mcp]       # MCP server only
pip install llx[litellm]    # LiteLLM proxy
pip install llx[code2llm]   # Code analysis
pip install llx[redup]      # Duplication detection
pip install llx[vallm]      # Code validation

Quick Start

# Analyze project and get model recommendation
llx analyze ./my-project

# Quick model selection
llx select .

# With task hint
llx select . --task refactor

# Point to pre-existing .toon files
llx analyze . --toon-dir ./analysis/

# JSON output for CI/CD
llx analyze . --json

# Chat with auto-selected model
llx chat . --prompt "Refactor the god modules"

# Force local model
llx select . --local

Model Selection Logic

Metric Premium (โ‰ฅ) Balanced (โ‰ฅ) Cheap (โ‰ฅ) Free
Files 50 10 3 <3
Lines 20,000 5,000 500 <500
Avg CC 6.0 4.0 2.0 <2.0
Max fan-out 30 10 โ€” โ€”
Max CC 25 15 โ€” โ€”
Dup groups 15 5 โ€” โ€”
Dep cycles any โ€” โ€” โ€”

Privacy & Anonymization (NEW)

LLX provides reversible anonymization to protect sensitive data when sending to LLMs:

Features

  • Text anonymization: Emails, API keys, passwords, PESEL, credit cards
  • Project-level: AST-based code anonymization (variables, functions, classes)
  • Round-trip: Anonymize โ†’ Send to LLM โ†’ Deanonymize response
  • Persistent mapping: Save/restore context for later deanonymization

Quick Usage

from llx.privacy import quick_anonymize, quick_deanonymize

# Simple text anonymization
result = quick_anonymize("Email: user@example.com, API: sk-abc123")
print(result.text)  # "Email: [EMAIL_A1B2], API: [APIKEY_C3D4]"

# Later: restore original values
restored = quick_deanonymize(llm_response, result.mapping)

Project-Level Anonymization

from llx.privacy.project import AnonymizationContext, ProjectAnonymizer
from llx.privacy.deanonymize import ProjectDeanonymizer

# Anonymize entire project
ctx = AnonymizationContext(project_path="./my-project")
anonymizer = ProjectAnonymizer(ctx)
result = anonymizer.anonymize_project()

# Save context for later
ctx.save("./my-project.anon.json")

# Deanonymize LLM response
deanonymizer = ProjectDeanonymizer(ctx)
restored = deanonymizer.deanonymize_chat_response(llm_response)

MCP Tools

// Scan for sensitive data
{"tool": "llx_privacy_scan", "text": "Email: user@example.com"}

// Anonymize project
{"tool": "llx_project_anonymize", "path": "./my-project", "output_dir": "./anon"}

// Deanonymize response
{"tool": "llx_project_deanonymize", "context_path": "./anon/.anonymization_context.json", "text": "Fix fn_ABC123"}

See docs/PRIVACY.md and examples/privacy/ for complete documentation.

Real-World Selection Examples

Project Files Lines CCฬ„ Max CC Fan-out Tier
Single script 1 80 2.0 4 0 free
Small CLI 5 600 3.0 8 3 cheap
preLLM 31 8,900 5.0 28 30 premium
vallm 56 8,604 3.5 42 โ€” balanced
code2llm 113 21,128 4.6 65 45 premium
Monorepo 500+ 100K+ 5.0+ 30+ 50+ premium

LiteLLM Proxy

llx proxy config     # Generate litellm_config.yaml
llx proxy start      # Start proxy on :4000
llx proxy status     # Check if running

Configure IDE tools to point at http://localhost:4000:

Tool Config
Roo Code / Cline "apiBase": "http://localhost:4000/v1"
Continue.dev "apiBase": "http://localhost:4000/v1"
Aider OPENAI_API_BASE=http://localhost:4000
Claude Code ANTHROPIC_BASE_URL=http://localhost:4000
Cursor / Windsurf OpenAI-compatible endpoint

Configuration

llx init  # Creates llx.toml with defaults

Environment variables: LLX_LITELLM_URL, LLX_DEFAULT_TIER, LLX_PROXY_PORT, LLX_VERBOSE.

Python API

from llx import analyze_project, select_model, LlxConfig

metrics = analyze_project("./my-project")
result = select_model(metrics)
print(result.model_id)   # "claude-opus-4-20250514"
print(result.explain())   # Human-readable reasoning

Integration with wronai Toolchain

Tool Role llx Uses
code2llm Static analysis CC, fan-out, cycles, hotspots
redup Duplication detection Groups, recoverable lines
vallm Code validation Pass rate, issue count
llx Model routing + MCP server Consumes all above

Package Structure

llx/
โ”œโ”€โ”€ __init__.py              # Public API (30L)
โ”œโ”€โ”€ config.py                # Config loader (160L)
โ”œโ”€โ”€ mcp/                     # MCP server (NEW)
โ”‚   โ”œโ”€โ”€ __init__.py          # Module init
โ”‚   โ”œโ”€โ”€ server.py            # MCP server dispatcher (40L)
โ”‚   โ”œโ”€โ”€ tools.py             # 7 MCP tool definitions (250L)
โ”‚   โ””โ”€โ”€ __main__.py          # python -m llx.mcp
โ”œโ”€โ”€ analysis/
โ”‚   โ”œโ”€โ”€ collector.py         # Metrics from .toon, filesystem (280L)
โ”‚   โ””โ”€โ”€ runner.py            # Tool invocation (80L)
โ”œโ”€โ”€ routing/
โ”‚   โ”œโ”€โ”€ selector.py          # Metric โ†’ tier mapping (200L)
โ”‚   โ””โ”€โ”€ client.py            # LiteLLM client wrapper (150L)
โ”œโ”€โ”€ integrations/
โ”‚   โ”œโ”€โ”€ context_builder.py   # .toon โ†’ LLM context (130L)
โ”‚   โ””โ”€โ”€ proxy.py             # LiteLLM proxy management (100L)
โ””โ”€โ”€ cli/
    โ”œโ”€โ”€ app.py               # Commands (300L, max CC โ‰ค 8)
    โ””โ”€โ”€ formatters.py        # Output formatting (340L, max CC โ‰ค 10)

Total: ~1,600 lines across 12 modules. No file exceeds 350L. Max CC โ‰ค 10.

Compare: preLLM had 8,900 lines with 3 god modules (cli.py: 999L, core.py: 893L, trace.py: 509L).

Architecture Improvements (v0.1.7)

  • โœ… Refactored 6 high-CC functions to meet targets (CCฬ„ โ‰ค 2.5, max CC โ‰ค 16)
  • โœ… Added complete MCP server with 7 tools for Claude Desktop integration
  • โœ… Fixed import resolution issues reported by vallm
  • โœ… Enhanced test coverage for MCP functionality
  • โœ… Modular design with single-responsibility functions

License

Licensed under Apache-2.0.

Author

Tom Sapletta

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

llx-0.1.52.tar.gz (300.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

llx-0.1.52-py3-none-any.whl (341.1 kB view details)

Uploaded Python 3

File details

Details for the file llx-0.1.52.tar.gz.

File metadata

  • Download URL: llx-0.1.52.tar.gz
  • Upload date:
  • Size: 300.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for llx-0.1.52.tar.gz
Algorithm Hash digest
SHA256 d5c8a378277656a66b4332c967e122e2c5ac8953d30e4251bb68392cbedf7b90
MD5 f1d753f426227aaf6812e48cf37e1847
BLAKE2b-256 8ff3670df3430a3932ff6232413f97f52965991bf880ab158731455085a495b2

See more details on using hashes here.

File details

Details for the file llx-0.1.52-py3-none-any.whl.

File metadata

  • Download URL: llx-0.1.52-py3-none-any.whl
  • Upload date:
  • Size: 341.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for llx-0.1.52-py3-none-any.whl
Algorithm Hash digest
SHA256 23fc06a32cb0d901bddf662c4c54d632181466e48c7dee6e4a58a54b2d3b927d
MD5 c192ac96f5555a974c8b2b4ae973b9bd
BLAKE2b-256 aaba6499bcabfee58fc92fd909b90b037fa4d0f87d8feaa0ee72f0201ec69989

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page