llx 0.1.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- llx-0.1.1/LICENSE +15 -0
- llx-0.1.1/PKG-INFO +247 -0
- llx-0.1.1/README.md +198 -0
- llx-0.1.1/llx/__init__.py +29 -0
- llx-0.1.1/llx/__main__.py +4 -0
- llx-0.1.1/llx/analysis/__init__.py +1 -0
- llx-0.1.1/llx/analysis/collector.py +411 -0
- llx-0.1.1/llx/analysis/runner.py +80 -0
- llx-0.1.1/llx/cli/__init__.py +5 -0
- llx-0.1.1/llx/cli/app.py +235 -0
- llx-0.1.1/llx/cli/formatters.py +126 -0
- llx-0.1.1/llx/config.py +203 -0
- llx-0.1.1/llx/integrations/__init__.py +1 -0
- llx-0.1.1/llx/integrations/context_builder.py +175 -0
- llx-0.1.1/llx/integrations/proxy.py +131 -0
- llx-0.1.1/llx/routing/__init__.py +1 -0
- llx-0.1.1/llx/routing/client.py +198 -0
- llx-0.1.1/llx/routing/selector.py +259 -0
- llx-0.1.1/llx.egg-info/PKG-INFO +247 -0
- llx-0.1.1/llx.egg-info/SOURCES.txt +25 -0
- llx-0.1.1/llx.egg-info/dependency_links.txt +1 -0
- llx-0.1.1/llx.egg-info/entry_points.txt +2 -0
- llx-0.1.1/llx.egg-info/requires.txt +37 -0
- llx-0.1.1/llx.egg-info/top_level.txt +1 -0
- llx-0.1.1/pyproject.toml +70 -0
- llx-0.1.1/setup.cfg +4 -0
- llx-0.1.1/tests/test_core.py +213 -0
llx-0.1.1/LICENSE
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
you may not use this file except in compliance with the License.
|
|
7
|
+
You may obtain a copy of the License at
|
|
8
|
+
|
|
9
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
|
|
11
|
+
Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
See the License for the specific language governing permissions and
|
|
15
|
+
limitations under the License.
|
llx-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: llx
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Intelligent LLM model router driven by real code metrics — successor to preLLM
|
|
5
|
+
Author-email: Tom Sapletta <tom@sapletta.com>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/wronai/llx
|
|
8
|
+
Project-URL: Repository, https://github.com/wronai/llx
|
|
9
|
+
Keywords: llm,code-analysis,model-routing,litellm,code2llm,developer-tools
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Software Development :: Quality Assurance
|
|
17
|
+
Requires-Python: >=3.10
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: typer>=0.12
|
|
21
|
+
Requires-Dist: rich>=13.0
|
|
22
|
+
Requires-Dist: pydantic>=2.0
|
|
23
|
+
Requires-Dist: pydantic-settings>=2.0
|
|
24
|
+
Requires-Dist: tomli>=2.0; python_version < "3.11"
|
|
25
|
+
Requires-Dist: httpx>=0.27
|
|
26
|
+
Requires-Dist: pyyaml>=6.0
|
|
27
|
+
Provides-Extra: litellm
|
|
28
|
+
Requires-Dist: litellm>=1.40; extra == "litellm"
|
|
29
|
+
Provides-Extra: code2llm
|
|
30
|
+
Requires-Dist: code2llm>=0.9; extra == "code2llm"
|
|
31
|
+
Provides-Extra: redup
|
|
32
|
+
Requires-Dist: redup>=0.4; extra == "redup"
|
|
33
|
+
Provides-Extra: vallm
|
|
34
|
+
Requires-Dist: vallm>=0.1; extra == "vallm"
|
|
35
|
+
Provides-Extra: ollama
|
|
36
|
+
Requires-Dist: ollama>=0.3; extra == "ollama"
|
|
37
|
+
Provides-Extra: all
|
|
38
|
+
Requires-Dist: litellm>=1.40; extra == "all"
|
|
39
|
+
Requires-Dist: code2llm>=0.9; extra == "all"
|
|
40
|
+
Requires-Dist: redup>=0.4; extra == "all"
|
|
41
|
+
Requires-Dist: vallm>=0.1; extra == "all"
|
|
42
|
+
Requires-Dist: ollama>=0.3; extra == "all"
|
|
43
|
+
Provides-Extra: dev
|
|
44
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
45
|
+
Requires-Dist: pytest-cov>=5.0; extra == "dev"
|
|
46
|
+
Requires-Dist: ruff>=0.5; extra == "dev"
|
|
47
|
+
Requires-Dist: mypy>=1.10; extra == "dev"
|
|
48
|
+
Dynamic: license-file
|
|
49
|
+
|
|
50
|
+
# llx
|
|
51
|
+
|
|
52
|
+
**Intelligent LLM model router driven by real code metrics.**
|
|
53
|
+
|
|
54
|
+
[](https://pypi.org/project/llx/)
|
|
55
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
56
|
+
[](https://python.org)
|
|
57
|
+
|
|
58
|
+
**Successor to [preLLM](https://github.com/wronai/prellm)** — rebuilt with modular architecture, no god modules, and metric-driven routing.
|
|
59
|
+
|
|
60
|
+
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.
|
|
61
|
+
|
|
62
|
+
**Principle**: larger + more coupled + more complex → stronger (and more expensive) model.
|
|
63
|
+
|
|
64
|
+
## Why llx? (Lessons from preLLM)
|
|
65
|
+
|
|
66
|
+
preLLM proved the concept but had architectural issues that llx resolves:
|
|
67
|
+
|
|
68
|
+
| Problem in preLLM | llx Solution |
|
|
69
|
+
|---|---|
|
|
70
|
+
| `cli.py`: 999 lines, CC=30 (`main`), CC=27 (`query`) | CLI split into `app.py` + `formatters.py`, max CC ≤ 8 |
|
|
71
|
+
| `core.py`: 893 lines god module | Config, analysis, routing in separate modules (≤250L each) |
|
|
72
|
+
| `trace.py`: 509 lines, CC=28 (`to_stdout`) | Output formatting as dedicated functions |
|
|
73
|
+
| Hardcoded model selection | Metric-driven thresholds from code2llm .toon data |
|
|
74
|
+
| No duplication/validation awareness | Integrates redup + vallm for richer metrics |
|
|
75
|
+
|
|
76
|
+
## Architecture
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
80
|
+
│ IDE / Agent Layer │
|
|
81
|
+
│ Roo Code │ Cline │ Continue.dev │ Aider │ Claude Code │
|
|
82
|
+
│ (point at localhost:4000 as OpenAI-compatible API) │
|
|
83
|
+
└─────────────────┬───────────────────────────────────────────┘
|
|
84
|
+
│
|
|
85
|
+
┌─────────────────▼───────────────────────────────────────────┐
|
|
86
|
+
│ LiteLLM Proxy (localhost:4000) │
|
|
87
|
+
│ ┌──────────┐ ┌──────────────┐ ┌────────────────────┐ │
|
|
88
|
+
│ │ Router │ │ Semantic │ │ Cost Tracking │ │
|
|
89
|
+
│ │ (metrics)│ │ Cache (Redis)│ │ + Budget Limits │ │
|
|
90
|
+
│ └────┬─────┘ └──────────────┘ └────────────────────┘ │
|
|
91
|
+
└───────┼─────────────────────────────────────────────────────┘
|
|
92
|
+
│
|
|
93
|
+
┌────┼────────────────────────────────────────┐
|
|
94
|
+
│ │ Model Tiers │
|
|
95
|
+
│ ├── premium: Claude Opus 4 │
|
|
96
|
+
│ ├── balanced: Claude Sonnet 4 / GPT-5 │
|
|
97
|
+
│ ├── cheap: Claude Haiku 4.5 │
|
|
98
|
+
│ ├── free: Gemini 2.5 Pro │
|
|
99
|
+
│ ├── openrouter: 300+ models (fallback) │
|
|
100
|
+
│ └── local: Ollama (Qwen2.5-Coder) │
|
|
101
|
+
└──────────────────────────────────────────────┘
|
|
102
|
+
│
|
|
103
|
+
┌───────▼─────────────────────────────────────────────────────┐
|
|
104
|
+
│ Code Analysis Pipeline │
|
|
105
|
+
│ code2llm → redup → vallm → llx │
|
|
106
|
+
│ (metrics → duplication → validation → model selection) │
|
|
107
|
+
└─────────────────────────────────────────────────────────────┘
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Installation
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
pip install llx
|
|
114
|
+
|
|
115
|
+
# With integrations
|
|
116
|
+
pip install llx[all] # Everything
|
|
117
|
+
pip install llx[litellm] # LiteLLM proxy
|
|
118
|
+
pip install llx[code2llm] # Code analysis
|
|
119
|
+
pip install llx[redup] # Duplication detection
|
|
120
|
+
pip install llx[vallm] # Code validation
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Quick Start
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Analyze project and get model recommendation
|
|
127
|
+
llx analyze ./my-project
|
|
128
|
+
|
|
129
|
+
# Quick model selection
|
|
130
|
+
llx select .
|
|
131
|
+
|
|
132
|
+
# With task hint
|
|
133
|
+
llx select . --task refactor
|
|
134
|
+
|
|
135
|
+
# Point to pre-existing .toon files
|
|
136
|
+
llx analyze . --toon-dir ./analysis/
|
|
137
|
+
|
|
138
|
+
# JSON output for CI/CD
|
|
139
|
+
llx analyze . --json
|
|
140
|
+
|
|
141
|
+
# Chat with auto-selected model
|
|
142
|
+
llx chat . --prompt "Refactor the god modules"
|
|
143
|
+
|
|
144
|
+
# Force local model
|
|
145
|
+
llx select . --local
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Model Selection Logic
|
|
149
|
+
|
|
150
|
+
| Metric | Premium (≥) | Balanced (≥) | Cheap (≥) | Free |
|
|
151
|
+
|--------|-------------|--------------|-----------|------|
|
|
152
|
+
| Files | 50 | 10 | 3 | <3 |
|
|
153
|
+
| Lines | 20,000 | 5,000 | 500 | <500 |
|
|
154
|
+
| Avg CC | 6.0 | 4.0 | 2.0 | <2.0 |
|
|
155
|
+
| Max fan-out | 30 | 10 | — | — |
|
|
156
|
+
| Max CC | 25 | 15 | — | — |
|
|
157
|
+
| Dup groups | 15 | 5 | — | — |
|
|
158
|
+
| Dep cycles | any | — | — | — |
|
|
159
|
+
|
|
160
|
+
## Real-World Selection Examples
|
|
161
|
+
|
|
162
|
+
| Project | Files | Lines | CC̄ | Max CC | Fan-out | Tier |
|
|
163
|
+
|---------|-------|-------|-----|--------|---------|------|
|
|
164
|
+
| Single script | 1 | 80 | 2.0 | 4 | 0 | **free** |
|
|
165
|
+
| Small CLI | 5 | 600 | 3.0 | 8 | 3 | **cheap** |
|
|
166
|
+
| **preLLM** | **31** | **8,900** | **5.0** | **28** | **30** | **premium** |
|
|
167
|
+
| vallm | 56 | 8,604 | 3.5 | 42 | — | **balanced** |
|
|
168
|
+
| code2llm | 113 | 21,128 | 4.6 | 65 | 45 | **premium** |
|
|
169
|
+
| Monorepo | 500+ | 100K+ | 5.0+ | 30+ | 50+ | **premium** |
|
|
170
|
+
|
|
171
|
+
## LiteLLM Proxy
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
llx proxy config # Generate litellm_config.yaml
|
|
175
|
+
llx proxy start # Start proxy on :4000
|
|
176
|
+
llx proxy status # Check if running
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Configure IDE tools to point at `http://localhost:4000`:
|
|
180
|
+
|
|
181
|
+
| Tool | Config |
|
|
182
|
+
|------|--------|
|
|
183
|
+
| Roo Code / Cline | `"apiBase": "http://localhost:4000/v1"` |
|
|
184
|
+
| Continue.dev | `"apiBase": "http://localhost:4000/v1"` |
|
|
185
|
+
| Aider | `OPENAI_API_BASE=http://localhost:4000` |
|
|
186
|
+
| Claude Code | `ANTHROPIC_BASE_URL=http://localhost:4000` |
|
|
187
|
+
| Cursor / Windsurf | OpenAI-compatible endpoint |
|
|
188
|
+
|
|
189
|
+
## Configuration
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
llx init # Creates llx.toml with defaults
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Environment variables: `LLX_LITELLM_URL`, `LLX_DEFAULT_TIER`, `LLX_PROXY_PORT`, `LLX_VERBOSE`.
|
|
196
|
+
|
|
197
|
+
## Python API
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
from llx import analyze_project, select_model, LlxConfig
|
|
201
|
+
|
|
202
|
+
metrics = analyze_project("./my-project")
|
|
203
|
+
result = select_model(metrics)
|
|
204
|
+
print(result.model_id) # "claude-opus-4-20250514"
|
|
205
|
+
print(result.explain()) # Human-readable reasoning
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Integration with wronai Toolchain
|
|
209
|
+
|
|
210
|
+
| Tool | Role | llx Uses |
|
|
211
|
+
|------|------|----------|
|
|
212
|
+
| [code2llm](https://github.com/wronai/code2llm) | Static analysis | CC, fan-out, cycles, hotspots |
|
|
213
|
+
| [redup](https://github.com/semcod/redup) | Duplication detection | Groups, recoverable lines |
|
|
214
|
+
| [vallm](https://github.com/semcod/vallm) | Code validation | Pass rate, issue count |
|
|
215
|
+
| **llx** | **Model routing** | **Consumes all above** |
|
|
216
|
+
|
|
217
|
+
## Package Structure
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
llx/
|
|
221
|
+
├── __init__.py # Public API (30L)
|
|
222
|
+
├── config.py # Config loader (160L)
|
|
223
|
+
├── analysis/
|
|
224
|
+
│ ├── collector.py # Metrics from .toon, filesystem (280L)
|
|
225
|
+
│ └── runner.py # Tool invocation (80L)
|
|
226
|
+
├── routing/
|
|
227
|
+
│ ├── selector.py # Metric → tier mapping (200L)
|
|
228
|
+
│ └── client.py # LiteLLM client wrapper (150L)
|
|
229
|
+
├── integrations/
|
|
230
|
+
│ ├── context_builder.py # .toon → LLM context (130L)
|
|
231
|
+
│ └── proxy.py # LiteLLM proxy management (100L)
|
|
232
|
+
└── cli/
|
|
233
|
+
├── app.py # Commands (230L, max CC ≤ 8)
|
|
234
|
+
└── formatters.py # Output formatting (120L)
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**Total**: ~1,280 lines across 10 modules. No file exceeds 300L. Max CC ≤ 8.
|
|
238
|
+
|
|
239
|
+
Compare: preLLM had 8,900 lines with 3 god modules (cli.py: 999L, core.py: 893L, trace.py: 509L).
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
Apache License 2.0 - see [LICENSE](LICENSE) for details.
|
|
244
|
+
|
|
245
|
+
## Author
|
|
246
|
+
|
|
247
|
+
Created by **Tom Sapletta** - [tom@sapletta.com](mailto:tom@sapletta.com)
|
llx-0.1.1/README.md
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# llx
|
|
2
|
+
|
|
3
|
+
**Intelligent LLM model router driven by real code metrics.**
|
|
4
|
+
|
|
5
|
+
[](https://pypi.org/project/llx/)
|
|
6
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
7
|
+
[](https://python.org)
|
|
8
|
+
|
|
9
|
+
**Successor to [preLLM](https://github.com/wronai/prellm)** — rebuilt with modular architecture, no god modules, and metric-driven routing.
|
|
10
|
+
|
|
11
|
+
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.
|
|
12
|
+
|
|
13
|
+
**Principle**: larger + more coupled + more complex → stronger (and more expensive) model.
|
|
14
|
+
|
|
15
|
+
## Why llx? (Lessons from preLLM)
|
|
16
|
+
|
|
17
|
+
preLLM proved the concept but had architectural issues that llx resolves:
|
|
18
|
+
|
|
19
|
+
| Problem in preLLM | llx Solution |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `cli.py`: 999 lines, CC=30 (`main`), CC=27 (`query`) | CLI split into `app.py` + `formatters.py`, max CC ≤ 8 |
|
|
22
|
+
| `core.py`: 893 lines god module | Config, analysis, routing in separate modules (≤250L each) |
|
|
23
|
+
| `trace.py`: 509 lines, CC=28 (`to_stdout`) | Output formatting as dedicated functions |
|
|
24
|
+
| Hardcoded model selection | Metric-driven thresholds from code2llm .toon data |
|
|
25
|
+
| No duplication/validation awareness | Integrates redup + vallm for richer metrics |
|
|
26
|
+
|
|
27
|
+
## Architecture
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
31
|
+
│ IDE / Agent Layer │
|
|
32
|
+
│ Roo Code │ Cline │ Continue.dev │ Aider │ Claude Code │
|
|
33
|
+
│ (point at localhost:4000 as OpenAI-compatible API) │
|
|
34
|
+
└─────────────────┬───────────────────────────────────────────┘
|
|
35
|
+
│
|
|
36
|
+
┌─────────────────▼───────────────────────────────────────────┐
|
|
37
|
+
│ LiteLLM Proxy (localhost:4000) │
|
|
38
|
+
│ ┌──────────┐ ┌──────────────┐ ┌────────────────────┐ │
|
|
39
|
+
│ │ Router │ │ Semantic │ │ Cost Tracking │ │
|
|
40
|
+
│ │ (metrics)│ │ Cache (Redis)│ │ + Budget Limits │ │
|
|
41
|
+
│ └────┬─────┘ └──────────────┘ └────────────────────┘ │
|
|
42
|
+
└───────┼─────────────────────────────────────────────────────┘
|
|
43
|
+
│
|
|
44
|
+
┌────┼────────────────────────────────────────┐
|
|
45
|
+
│ │ Model Tiers │
|
|
46
|
+
│ ├── premium: Claude Opus 4 │
|
|
47
|
+
│ ├── balanced: Claude Sonnet 4 / GPT-5 │
|
|
48
|
+
│ ├── cheap: Claude Haiku 4.5 │
|
|
49
|
+
│ ├── free: Gemini 2.5 Pro │
|
|
50
|
+
│ ├── openrouter: 300+ models (fallback) │
|
|
51
|
+
│ └── local: Ollama (Qwen2.5-Coder) │
|
|
52
|
+
└──────────────────────────────────────────────┘
|
|
53
|
+
│
|
|
54
|
+
┌───────▼─────────────────────────────────────────────────────┐
|
|
55
|
+
│ Code Analysis Pipeline │
|
|
56
|
+
│ code2llm → redup → vallm → llx │
|
|
57
|
+
│ (metrics → duplication → validation → model selection) │
|
|
58
|
+
└─────────────────────────────────────────────────────────────┘
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install llx
|
|
65
|
+
|
|
66
|
+
# With integrations
|
|
67
|
+
pip install llx[all] # Everything
|
|
68
|
+
pip install llx[litellm] # LiteLLM proxy
|
|
69
|
+
pip install llx[code2llm] # Code analysis
|
|
70
|
+
pip install llx[redup] # Duplication detection
|
|
71
|
+
pip install llx[vallm] # Code validation
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Quick Start
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Analyze project and get model recommendation
|
|
78
|
+
llx analyze ./my-project
|
|
79
|
+
|
|
80
|
+
# Quick model selection
|
|
81
|
+
llx select .
|
|
82
|
+
|
|
83
|
+
# With task hint
|
|
84
|
+
llx select . --task refactor
|
|
85
|
+
|
|
86
|
+
# Point to pre-existing .toon files
|
|
87
|
+
llx analyze . --toon-dir ./analysis/
|
|
88
|
+
|
|
89
|
+
# JSON output for CI/CD
|
|
90
|
+
llx analyze . --json
|
|
91
|
+
|
|
92
|
+
# Chat with auto-selected model
|
|
93
|
+
llx chat . --prompt "Refactor the god modules"
|
|
94
|
+
|
|
95
|
+
# Force local model
|
|
96
|
+
llx select . --local
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Model Selection Logic
|
|
100
|
+
|
|
101
|
+
| Metric | Premium (≥) | Balanced (≥) | Cheap (≥) | Free |
|
|
102
|
+
|--------|-------------|--------------|-----------|------|
|
|
103
|
+
| Files | 50 | 10 | 3 | <3 |
|
|
104
|
+
| Lines | 20,000 | 5,000 | 500 | <500 |
|
|
105
|
+
| Avg CC | 6.0 | 4.0 | 2.0 | <2.0 |
|
|
106
|
+
| Max fan-out | 30 | 10 | — | — |
|
|
107
|
+
| Max CC | 25 | 15 | — | — |
|
|
108
|
+
| Dup groups | 15 | 5 | — | — |
|
|
109
|
+
| Dep cycles | any | — | — | — |
|
|
110
|
+
|
|
111
|
+
## Real-World Selection Examples
|
|
112
|
+
|
|
113
|
+
| Project | Files | Lines | CC̄ | Max CC | Fan-out | Tier |
|
|
114
|
+
|---------|-------|-------|-----|--------|---------|------|
|
|
115
|
+
| Single script | 1 | 80 | 2.0 | 4 | 0 | **free** |
|
|
116
|
+
| Small CLI | 5 | 600 | 3.0 | 8 | 3 | **cheap** |
|
|
117
|
+
| **preLLM** | **31** | **8,900** | **5.0** | **28** | **30** | **premium** |
|
|
118
|
+
| vallm | 56 | 8,604 | 3.5 | 42 | — | **balanced** |
|
|
119
|
+
| code2llm | 113 | 21,128 | 4.6 | 65 | 45 | **premium** |
|
|
120
|
+
| Monorepo | 500+ | 100K+ | 5.0+ | 30+ | 50+ | **premium** |
|
|
121
|
+
|
|
122
|
+
## LiteLLM Proxy
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
llx proxy config # Generate litellm_config.yaml
|
|
126
|
+
llx proxy start # Start proxy on :4000
|
|
127
|
+
llx proxy status # Check if running
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Configure IDE tools to point at `http://localhost:4000`:
|
|
131
|
+
|
|
132
|
+
| Tool | Config |
|
|
133
|
+
|------|--------|
|
|
134
|
+
| Roo Code / Cline | `"apiBase": "http://localhost:4000/v1"` |
|
|
135
|
+
| Continue.dev | `"apiBase": "http://localhost:4000/v1"` |
|
|
136
|
+
| Aider | `OPENAI_API_BASE=http://localhost:4000` |
|
|
137
|
+
| Claude Code | `ANTHROPIC_BASE_URL=http://localhost:4000` |
|
|
138
|
+
| Cursor / Windsurf | OpenAI-compatible endpoint |
|
|
139
|
+
|
|
140
|
+
## Configuration
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
llx init # Creates llx.toml with defaults
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Environment variables: `LLX_LITELLM_URL`, `LLX_DEFAULT_TIER`, `LLX_PROXY_PORT`, `LLX_VERBOSE`.
|
|
147
|
+
|
|
148
|
+
## Python API
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
from llx import analyze_project, select_model, LlxConfig
|
|
152
|
+
|
|
153
|
+
metrics = analyze_project("./my-project")
|
|
154
|
+
result = select_model(metrics)
|
|
155
|
+
print(result.model_id) # "claude-opus-4-20250514"
|
|
156
|
+
print(result.explain()) # Human-readable reasoning
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Integration with wronai Toolchain
|
|
160
|
+
|
|
161
|
+
| Tool | Role | llx Uses |
|
|
162
|
+
|------|------|----------|
|
|
163
|
+
| [code2llm](https://github.com/wronai/code2llm) | Static analysis | CC, fan-out, cycles, hotspots |
|
|
164
|
+
| [redup](https://github.com/semcod/redup) | Duplication detection | Groups, recoverable lines |
|
|
165
|
+
| [vallm](https://github.com/semcod/vallm) | Code validation | Pass rate, issue count |
|
|
166
|
+
| **llx** | **Model routing** | **Consumes all above** |
|
|
167
|
+
|
|
168
|
+
## Package Structure
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
llx/
|
|
172
|
+
├── __init__.py # Public API (30L)
|
|
173
|
+
├── config.py # Config loader (160L)
|
|
174
|
+
├── analysis/
|
|
175
|
+
│ ├── collector.py # Metrics from .toon, filesystem (280L)
|
|
176
|
+
│ └── runner.py # Tool invocation (80L)
|
|
177
|
+
├── routing/
|
|
178
|
+
│ ├── selector.py # Metric → tier mapping (200L)
|
|
179
|
+
│ └── client.py # LiteLLM client wrapper (150L)
|
|
180
|
+
├── integrations/
|
|
181
|
+
│ ├── context_builder.py # .toon → LLM context (130L)
|
|
182
|
+
│ └── proxy.py # LiteLLM proxy management (100L)
|
|
183
|
+
└── cli/
|
|
184
|
+
├── app.py # Commands (230L, max CC ≤ 8)
|
|
185
|
+
└── formatters.py # Output formatting (120L)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**Total**: ~1,280 lines across 10 modules. No file exceeds 300L. Max CC ≤ 8.
|
|
189
|
+
|
|
190
|
+
Compare: preLLM had 8,900 lines with 3 god modules (cli.py: 999L, core.py: 893L, trace.py: 509L).
|
|
191
|
+
|
|
192
|
+
## License
|
|
193
|
+
|
|
194
|
+
Apache License 2.0 - see [LICENSE](LICENSE) for details.
|
|
195
|
+
|
|
196
|
+
## Author
|
|
197
|
+
|
|
198
|
+
Created by **Tom Sapletta** - [tom@sapletta.com](mailto:tom@sapletta.com)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"""llx — Intelligent LLM model router driven by real code metrics.
|
|
2
|
+
|
|
3
|
+
Successor to preLLM. Integrates code2llm (analysis), redup (duplication),
|
|
4
|
+
vallm (validation) with LiteLLM for metric-aware model selection.
|
|
5
|
+
|
|
6
|
+
Key difference from preLLM: modular architecture (no god modules),
|
|
7
|
+
metric-driven routing instead of hardcoded model selection,
|
|
8
|
+
and clean separation of analysis/routing/client layers.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
from llx import analyze_project, select_model, LlxConfig
|
|
12
|
+
|
|
13
|
+
metrics = analyze_project("./my-repo")
|
|
14
|
+
model = select_model(metrics)
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
__version__ = "0.1.1"
|
|
18
|
+
|
|
19
|
+
from llx.analysis.collector import ProjectMetrics, analyze_project
|
|
20
|
+
from llx.routing.selector import ModelTier, select_model
|
|
21
|
+
from llx.config import LlxConfig
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"analyze_project",
|
|
25
|
+
"select_model",
|
|
26
|
+
"ProjectMetrics",
|
|
27
|
+
"ModelTier",
|
|
28
|
+
"LlxConfig",
|
|
29
|
+
]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Analysis layer — collects project metrics from code2llm, redup, vallm, and filesystem."""
|