entropic-engine 1.0.0__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.
- entropic_engine-1.0.0/PKG-INFO +220 -0
- entropic_engine-1.0.0/README.md +164 -0
- entropic_engine-1.0.0/pyproject.toml +135 -0
- entropic_engine-1.0.0/setup.cfg +4 -0
- entropic_engine-1.0.0/src/entropic/__init__.py +93 -0
- entropic_engine-1.0.0/src/entropic/__main__.py +8 -0
- entropic_engine-1.0.0/src/entropic/app.py +983 -0
- entropic_engine-1.0.0/src/entropic/cli.py +292 -0
- entropic_engine-1.0.0/src/entropic/cli_download.py +137 -0
- entropic_engine-1.0.0/src/entropic/config/__init__.py +13 -0
- entropic_engine-1.0.0/src/entropic/config/loader.py +497 -0
- entropic_engine-1.0.0/src/entropic/config/schema.py +508 -0
- entropic_engine-1.0.0/src/entropic/core/__init__.py +86 -0
- entropic_engine-1.0.0/src/entropic/core/base.py +265 -0
- entropic_engine-1.0.0/src/entropic/core/commands.py +760 -0
- entropic_engine-1.0.0/src/entropic/core/compaction.py +448 -0
- entropic_engine-1.0.0/src/entropic/core/context.py +334 -0
- entropic_engine-1.0.0/src/entropic/core/directives.py +265 -0
- entropic_engine-1.0.0/src/entropic/core/engine.py +1459 -0
- entropic_engine-1.0.0/src/entropic/core/logging.py +144 -0
- entropic_engine-1.0.0/src/entropic/core/parser.py +172 -0
- entropic_engine-1.0.0/src/entropic/core/queue.py +369 -0
- entropic_engine-1.0.0/src/entropic/core/session.py +517 -0
- entropic_engine-1.0.0/src/entropic/core/tasks.py +530 -0
- entropic_engine-1.0.0/src/entropic/core/todos.py +335 -0
- entropic_engine-1.0.0/src/entropic/core/tool_validation.py +131 -0
- entropic_engine-1.0.0/src/entropic/data/default_config.yaml +108 -0
- entropic_engine-1.0.0/src/entropic/data/prompts/app_context.md +29 -0
- entropic_engine-1.0.0/src/entropic/data/prompts/constitution.md +32 -0
- entropic_engine-1.0.0/src/entropic/data/prompts/identity_code.md +28 -0
- entropic_engine-1.0.0/src/entropic/data/prompts/identity_normal.md +22 -0
- entropic_engine-1.0.0/src/entropic/data/prompts/identity_simple.md +26 -0
- entropic_engine-1.0.0/src/entropic/data/prompts/identity_thinking.md +54 -0
- entropic_engine-1.0.0/src/entropic/data/tools/bash/execute.json +18 -0
- entropic_engine-1.0.0/src/entropic/data/tools/diagnostics/check_errors.json +14 -0
- entropic_engine-1.0.0/src/entropic/data/tools/diagnostics/diagnostics.json +14 -0
- entropic_engine-1.0.0/src/entropic/data/tools/entropic/handoff.json +24 -0
- entropic_engine-1.0.0/src/entropic/data/tools/entropic/prune_context.json +13 -0
- entropic_engine-1.0.0/src/entropic/data/tools/entropic/todo_write.json +64 -0
- entropic_engine-1.0.0/src/entropic/data/tools/filesystem/edit_file.json +30 -0
- entropic_engine-1.0.0/src/entropic/data/tools/filesystem/read_file.json +14 -0
- entropic_engine-1.0.0/src/entropic/data/tools/filesystem/write_file.json +18 -0
- entropic_engine-1.0.0/src/entropic/data/tools/git/add.json +14 -0
- entropic_engine-1.0.0/src/entropic/data/tools/git/branch.json +14 -0
- entropic_engine-1.0.0/src/entropic/data/tools/git/checkout.json +14 -0
- entropic_engine-1.0.0/src/entropic/data/tools/git/commit.json +18 -0
- entropic_engine-1.0.0/src/entropic/data/tools/git/diff.json +18 -0
- entropic_engine-1.0.0/src/entropic/data/tools/git/log.json +18 -0
- entropic_engine-1.0.0/src/entropic/data/tools/git/reset.json +14 -0
- entropic_engine-1.0.0/src/entropic/data/tools/git/status.json +9 -0
- entropic_engine-1.0.0/src/entropic/inference/__init__.py +14 -0
- entropic_engine-1.0.0/src/entropic/inference/adapters/__init__.py +29 -0
- entropic_engine-1.0.0/src/entropic/inference/adapters/base.py +538 -0
- entropic_engine-1.0.0/src/entropic/inference/adapters/falcon.py +60 -0
- entropic_engine-1.0.0/src/entropic/inference/adapters/qwen2.py +286 -0
- entropic_engine-1.0.0/src/entropic/inference/adapters/qwen3.py +127 -0
- entropic_engine-1.0.0/src/entropic/inference/adapters/router.py +44 -0
- entropic_engine-1.0.0/src/entropic/inference/adapters/smollm3.py +31 -0
- entropic_engine-1.0.0/src/entropic/inference/backend.py +53 -0
- entropic_engine-1.0.0/src/entropic/inference/llama_cpp.py +457 -0
- entropic_engine-1.0.0/src/entropic/inference/orchestrator.py +627 -0
- entropic_engine-1.0.0/src/entropic/lsp/__init__.py +21 -0
- entropic_engine-1.0.0/src/entropic/lsp/base.py +294 -0
- entropic_engine-1.0.0/src/entropic/lsp/clangd_client.py +42 -0
- entropic_engine-1.0.0/src/entropic/lsp/manager.py +173 -0
- entropic_engine-1.0.0/src/entropic/lsp/pyright_client.py +81 -0
- entropic_engine-1.0.0/src/entropic/mcp/__init__.py +10 -0
- entropic_engine-1.0.0/src/entropic/mcp/bridge.py +181 -0
- entropic_engine-1.0.0/src/entropic/mcp/client.py +187 -0
- entropic_engine-1.0.0/src/entropic/mcp/manager.py +396 -0
- entropic_engine-1.0.0/src/entropic/mcp/provider.py +119 -0
- entropic_engine-1.0.0/src/entropic/mcp/servers/__init__.py +16 -0
- entropic_engine-1.0.0/src/entropic/mcp/servers/base.py +211 -0
- entropic_engine-1.0.0/src/entropic/mcp/servers/bash.py +166 -0
- entropic_engine-1.0.0/src/entropic/mcp/servers/diagnostics.py +154 -0
- entropic_engine-1.0.0/src/entropic/mcp/servers/entropic.py +199 -0
- entropic_engine-1.0.0/src/entropic/mcp/servers/external.py +750 -0
- entropic_engine-1.0.0/src/entropic/mcp/servers/file_tracker.py +124 -0
- entropic_engine-1.0.0/src/entropic/mcp/servers/filesystem.py +622 -0
- entropic_engine-1.0.0/src/entropic/mcp/servers/git.py +172 -0
- entropic_engine-1.0.0/src/entropic/mcp/tools.py +137 -0
- entropic_engine-1.0.0/src/entropic/prompts/__init__.py +261 -0
- entropic_engine-1.0.0/src/entropic/py.typed +0 -0
- entropic_engine-1.0.0/src/entropic/quality/__init__.py +8 -0
- entropic_engine-1.0.0/src/entropic/quality/analyzers/__init__.py +17 -0
- entropic_engine-1.0.0/src/entropic/quality/analyzers/base.py +88 -0
- entropic_engine-1.0.0/src/entropic/quality/analyzers/complexity.py +131 -0
- entropic_engine-1.0.0/src/entropic/quality/analyzers/docstrings.py +123 -0
- entropic_engine-1.0.0/src/entropic/quality/analyzers/structure.py +122 -0
- entropic_engine-1.0.0/src/entropic/quality/analyzers/typing.py +70 -0
- entropic_engine-1.0.0/src/entropic/quality/enforcer.py +239 -0
- entropic_engine-1.0.0/src/entropic/storage/__init__.py +16 -0
- entropic_engine-1.0.0/src/entropic/storage/backend.py +205 -0
- entropic_engine-1.0.0/src/entropic/storage/database.py +211 -0
- entropic_engine-1.0.0/src/entropic/storage/models.py +140 -0
- entropic_engine-1.0.0/src/entropic/storage/session.py +668 -0
- entropic_engine-1.0.0/src/entropic/ui/__init__.py +48 -0
- entropic_engine-1.0.0/src/entropic/ui/components.py +303 -0
- entropic_engine-1.0.0/src/entropic/ui/entropic.tcss +276 -0
- entropic_engine-1.0.0/src/entropic/ui/headless.py +324 -0
- entropic_engine-1.0.0/src/entropic/ui/presenter.py +318 -0
- entropic_engine-1.0.0/src/entropic/ui/themes.py +91 -0
- entropic_engine-1.0.0/src/entropic/ui/tui.py +1363 -0
- entropic_engine-1.0.0/src/entropic/ui/tui_presenter.py +178 -0
- entropic_engine-1.0.0/src/entropic/ui/voice_screen.py +680 -0
- entropic_engine-1.0.0/src/entropic/ui/voice_widgets.py +472 -0
- entropic_engine-1.0.0/src/entropic/ui/widgets.py +785 -0
- entropic_engine-1.0.0/src/entropic/voice/__init__.py +30 -0
- entropic_engine-1.0.0/src/entropic/voice/audio_io.py +837 -0
- entropic_engine-1.0.0/src/entropic/voice/client.py +514 -0
- entropic_engine-1.0.0/src/entropic/voice/context_compactor.py +500 -0
- entropic_engine-1.0.0/src/entropic/voice/controller.py +868 -0
- entropic_engine-1.0.0/src/entropic/voice/server.py +561 -0
- entropic_engine-1.0.0/src/entropic/voice/thinking_audio.py +255 -0
- entropic_engine-1.0.0/src/entropic_engine.egg-info/PKG-INFO +220 -0
- entropic_engine-1.0.0/src/entropic_engine.egg-info/SOURCES.txt +118 -0
- entropic_engine-1.0.0/src/entropic_engine.egg-info/dependency_links.txt +1 -0
- entropic_engine-1.0.0/src/entropic_engine.egg-info/entry_points.txt +3 -0
- entropic_engine-1.0.0/src/entropic_engine.egg-info/requires.txt +44 -0
- entropic_engine-1.0.0/src/entropic_engine.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: entropic-engine
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Local-first agentic inference engine with tier-based model routing
|
|
5
|
+
Author: Tristan VanFossen
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Keywords: ai,coding,assistant,llm,local
|
|
8
|
+
Classifier: Development Status :: 3 - Alpha
|
|
9
|
+
Classifier: Environment :: Console
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Topic :: Software Development
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: llama-cpp-python>=0.2.0
|
|
18
|
+
Requires-Dist: mcp>=1.0.0
|
|
19
|
+
Requires-Dist: pydantic>=2.0.0
|
|
20
|
+
Requires-Dist: pydantic-settings>=2.0.0
|
|
21
|
+
Requires-Dist: pyyaml>=6.0.0
|
|
22
|
+
Provides-Extra: tui
|
|
23
|
+
Requires-Dist: textual>=0.47.0; extra == "tui"
|
|
24
|
+
Requires-Dist: rich>=13.0.0; extra == "tui"
|
|
25
|
+
Requires-Dist: click>=8.0.0; extra == "tui"
|
|
26
|
+
Requires-Dist: pylspclient>=0.0.7; extra == "tui"
|
|
27
|
+
Provides-Extra: app
|
|
28
|
+
Requires-Dist: entropic-engine[tui]; extra == "app"
|
|
29
|
+
Requires-Dist: aiosqlite>=0.19.0; extra == "app"
|
|
30
|
+
Requires-Dist: httpx>=0.25.0; extra == "app"
|
|
31
|
+
Provides-Extra: all
|
|
32
|
+
Requires-Dist: entropic-engine[app,voice]; extra == "all"
|
|
33
|
+
Provides-Extra: dev
|
|
34
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest-bdd>=7.0.0; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: mypy>=1.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: black>=23.0.0; extra == "dev"
|
|
40
|
+
Requires-Dist: ruff>=0.1.0; extra == "dev"
|
|
41
|
+
Requires-Dist: pre-commit>=3.0.0; extra == "dev"
|
|
42
|
+
Requires-Dist: types-pyyaml>=6.0.0; extra == "dev"
|
|
43
|
+
Provides-Extra: voice
|
|
44
|
+
Requires-Dist: numpy<2.2,>=1.26; extra == "voice"
|
|
45
|
+
Requires-Dist: safetensors<0.5,>=0.4.0; extra == "voice"
|
|
46
|
+
Requires-Dist: huggingface-hub<0.28,>=0.24; extra == "voice"
|
|
47
|
+
Requires-Dist: einops==0.7; extra == "voice"
|
|
48
|
+
Requires-Dist: sentencepiece==0.2; extra == "voice"
|
|
49
|
+
Requires-Dist: sounddevice==0.5; extra == "voice"
|
|
50
|
+
Requires-Dist: sphn<0.2,>=0.1.4; extra == "voice"
|
|
51
|
+
Requires-Dist: torch>=2.2.0; extra == "voice"
|
|
52
|
+
Requires-Dist: aiohttp<3.12,>=3.10.5; extra == "voice"
|
|
53
|
+
Requires-Dist: websockets<14.0,>=12.0; extra == "voice"
|
|
54
|
+
Requires-Dist: accelerate>=0.30.0; extra == "voice"
|
|
55
|
+
Requires-Dist: torchao>=0.4.0; extra == "voice"
|
|
56
|
+
|
|
57
|
+
# Entropic
|
|
58
|
+
|
|
59
|
+
> Local-first agentic inference engine with tier-based model routing
|
|
60
|
+
|
|
61
|
+
This started as "I want to build a local-first Claude Code" — which turned out
|
|
62
|
+
to be quite the undertaking. The initial build was a tightly coupled TUI, but it
|
|
63
|
+
became clear pretty quickly that I was duplicating the same core inference engine
|
|
64
|
+
across other local projects wrapping llama-cpp-python. So it evolved into a
|
|
65
|
+
library: the inference engine, model orchestration, agentic loop, and tool
|
|
66
|
+
framework are all importable and reusable without dragging in a UI. The TUI ships
|
|
67
|
+
alongside it as one consumer, and doubles as a testbed for new ideas. There's also
|
|
68
|
+
a very broken voice interface via PersonaPlex that I'll get to eventually.
|
|
69
|
+
|
|
70
|
+
The name is a nod to how this actually works. Every handoff — human intent to
|
|
71
|
+
prompt, prompt to model, model to model across tiers — is a lossy translation.
|
|
72
|
+
Information decays at each boundary. That's the entropic process this engine tries
|
|
73
|
+
to manage: structured routing, context management, and tool-augmented reasoning to
|
|
74
|
+
lose as little as possible along the way. A bit of a nihilistic naming convention,
|
|
75
|
+
but the tier routing and model management do earn their keep in practice. There's
|
|
76
|
+
optimization work ahead, but the foundation is solid and I'm always open to new
|
|
77
|
+
directions.
|
|
78
|
+
|
|
79
|
+
## Architecture
|
|
80
|
+
|
|
81
|
+
Entropic is a **library first, application second**. The inference engine
|
|
82
|
+
(orchestrator, agentic loop, adapters, tool providers) is fully separable from
|
|
83
|
+
any UI. The bundled TUI is one consumer; headless automation, CI/CD agents, and
|
|
84
|
+
custom applications are equally supported.
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
pip install entropic-engine # Core library (inference, engine, tools)
|
|
88
|
+
pip install entropic-engine[app] # TUI application (includes tui + storage deps)
|
|
89
|
+
pip install entropic-engine[voice] # Voice interface (PersonaPlex)
|
|
90
|
+
pip install entropic-engine[all] # Everything
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
+-----------------------------------------------------+
|
|
95
|
+
| Application Layer (TUI / Headless / Custom) |
|
|
96
|
+
+-----------------------------------------------------+
|
|
97
|
+
| Engine | Orchestrator | Tools |
|
|
98
|
+
| - Agentic loop | - Tier routing | - Filesystem |
|
|
99
|
+
| - Directives | - Model swap | - Bash |
|
|
100
|
+
| - Compaction | - VRAM mgmt | - Diagnostics |
|
|
101
|
+
| - Context mgmt | - Adapters | - Git / Todo |
|
|
102
|
+
+-----------------------------------------------------+
|
|
103
|
+
| Inference Backend (llama-cpp-python) |
|
|
104
|
+
| - GGUF models, single-GPU, in-process |
|
|
105
|
+
+-----------------------------------------------------+
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Tier-Based Routing
|
|
109
|
+
|
|
110
|
+
A lightweight router model classifies each prompt and routes to the appropriate
|
|
111
|
+
tier. Only one main model is loaded at a time (VRAM constraint) — the
|
|
112
|
+
orchestrator handles dynamic swapping with lock-protected state transitions.
|
|
113
|
+
|
|
114
|
+
| Tier | Purpose | Typical Model |
|
|
115
|
+
|------|---------|---------------|
|
|
116
|
+
| **Thinking** | Complex reasoning, architecture, multi-step analysis | Qwen3-14B Q4_K_M |
|
|
117
|
+
| **Normal** | General conversation and tasks | Falcon-H1R-7B Q8_0 |
|
|
118
|
+
| **Code** | Code generation, editing, refactoring | Falcon-H1R-7B Q8_0 |
|
|
119
|
+
| **Simple** | Greetings, acknowledgments, short responses | (shares normal model) |
|
|
120
|
+
| **Router** | Prompt classification only | Qwen3-0.6B Q8_0 |
|
|
121
|
+
|
|
122
|
+
### Agentic Loop
|
|
123
|
+
|
|
124
|
+
The engine runs an autonomous tool-calling loop: generate -> parse tool calls ->
|
|
125
|
+
execute tools -> feed results back -> generate again. The loop continues until
|
|
126
|
+
the model produces a complete response or hits the iteration limit.
|
|
127
|
+
|
|
128
|
+
Tools communicate back to the engine via **directives** — structured signals
|
|
129
|
+
embedded in tool results that can trigger tier handoffs, context anchoring, and
|
|
130
|
+
state management without the model needing to orchestrate these concerns.
|
|
131
|
+
|
|
132
|
+
## Features
|
|
133
|
+
|
|
134
|
+
- **Fully Local** — All inference on your hardware via llama-cpp-python. No API keys.
|
|
135
|
+
- **Library API** — Embed the engine in your own application with `LibraryConfig`
|
|
136
|
+
- **Intelligent Routing** — Sub-second prompt classification routes to the right model tier
|
|
137
|
+
- **Single-GPU Orchestration** — Dynamic model swapping with VRAM-aware loading
|
|
138
|
+
- **Per-Model Adapters** — Model-specific chat templates, tool parsing, thinking block handling
|
|
139
|
+
- **Auto-Compaction** — Context summarization for long conversations
|
|
140
|
+
- **MCP Tools** — Filesystem, bash, diagnostics, git, and extensible tool servers
|
|
141
|
+
- **Headless Mode** — Full engine without TUI for automation and testing
|
|
142
|
+
- **TUI** — Terminal interface built on Textual with streaming, tool approval, voice input
|
|
143
|
+
|
|
144
|
+
## Requirements
|
|
145
|
+
|
|
146
|
+
- Linux (tested on Ubuntu 24.04)
|
|
147
|
+
- NVIDIA GPU with 16GB+ VRAM
|
|
148
|
+
- CUDA 12.4+
|
|
149
|
+
- Python 3.11+
|
|
150
|
+
|
|
151
|
+
## Quick Start
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
git clone https://github.com/tvanfossen/entropic.git
|
|
155
|
+
cd entropic
|
|
156
|
+
./install.sh app
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
The install script creates a virtual environment, detects CUDA, and installs
|
|
160
|
+
with the `[app]` extras (TUI + storage dependencies).
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
# Place GGUF models in ~/models/gguf/ (or configure paths in .entropic/config.local.yaml)
|
|
164
|
+
|
|
165
|
+
# Run interactive TUI
|
|
166
|
+
.venv/bin/entropic
|
|
167
|
+
|
|
168
|
+
# Or headless
|
|
169
|
+
.venv/bin/entropic --headless
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## CLI
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
entropic # Interactive TUI
|
|
176
|
+
entropic --headless # Headless mode (automation/testing)
|
|
177
|
+
entropic status # Show model and system status
|
|
178
|
+
entropic ask "question" # Single-shot question
|
|
179
|
+
entropic init # Initialize .entropic/ in current directory
|
|
180
|
+
entropic download <model> # Download model files
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## Configuration
|
|
184
|
+
|
|
185
|
+
Configuration loads in priority order (highest wins):
|
|
186
|
+
|
|
187
|
+
1. Built-in defaults
|
|
188
|
+
2. Global config (`~/.entropic/config.yaml`)
|
|
189
|
+
3. Project config (`.entropic/config.local.yaml`)
|
|
190
|
+
4. CLI arguments
|
|
191
|
+
|
|
192
|
+
Project context is provided via `.entropic/ENTROPIC.md` — a markdown file
|
|
193
|
+
describing the project that gets included in the system prompt.
|
|
194
|
+
|
|
195
|
+
## Library Usage
|
|
196
|
+
|
|
197
|
+
```python
|
|
198
|
+
from entropic import LibraryConfig, Orchestrator, Engine, ServerManager
|
|
199
|
+
|
|
200
|
+
config = LibraryConfig(
|
|
201
|
+
config_dir=Path("~/.myapp").expanduser(),
|
|
202
|
+
tiers={"normal": {"path": "model.gguf", "adapter": "qwen3"}},
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
orchestrator = Orchestrator(config.to_app_config())
|
|
206
|
+
await orchestrator.initialize()
|
|
207
|
+
|
|
208
|
+
server_manager = ServerManager(config.to_app_config())
|
|
209
|
+
await server_manager.initialize()
|
|
210
|
+
|
|
211
|
+
engine = Engine(orchestrator=orchestrator, server_manager=server_manager)
|
|
212
|
+
async for message in engine.run("Hello"):
|
|
213
|
+
print(message.content)
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
See `examples/hello-world/` and `examples/pychess/` for complete integrations.
|
|
217
|
+
|
|
218
|
+
## License
|
|
219
|
+
|
|
220
|
+
Apache-2.0
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# Entropic
|
|
2
|
+
|
|
3
|
+
> Local-first agentic inference engine with tier-based model routing
|
|
4
|
+
|
|
5
|
+
This started as "I want to build a local-first Claude Code" — which turned out
|
|
6
|
+
to be quite the undertaking. The initial build was a tightly coupled TUI, but it
|
|
7
|
+
became clear pretty quickly that I was duplicating the same core inference engine
|
|
8
|
+
across other local projects wrapping llama-cpp-python. So it evolved into a
|
|
9
|
+
library: the inference engine, model orchestration, agentic loop, and tool
|
|
10
|
+
framework are all importable and reusable without dragging in a UI. The TUI ships
|
|
11
|
+
alongside it as one consumer, and doubles as a testbed for new ideas. There's also
|
|
12
|
+
a very broken voice interface via PersonaPlex that I'll get to eventually.
|
|
13
|
+
|
|
14
|
+
The name is a nod to how this actually works. Every handoff — human intent to
|
|
15
|
+
prompt, prompt to model, model to model across tiers — is a lossy translation.
|
|
16
|
+
Information decays at each boundary. That's the entropic process this engine tries
|
|
17
|
+
to manage: structured routing, context management, and tool-augmented reasoning to
|
|
18
|
+
lose as little as possible along the way. A bit of a nihilistic naming convention,
|
|
19
|
+
but the tier routing and model management do earn their keep in practice. There's
|
|
20
|
+
optimization work ahead, but the foundation is solid and I'm always open to new
|
|
21
|
+
directions.
|
|
22
|
+
|
|
23
|
+
## Architecture
|
|
24
|
+
|
|
25
|
+
Entropic is a **library first, application second**. The inference engine
|
|
26
|
+
(orchestrator, agentic loop, adapters, tool providers) is fully separable from
|
|
27
|
+
any UI. The bundled TUI is one consumer; headless automation, CI/CD agents, and
|
|
28
|
+
custom applications are equally supported.
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
pip install entropic-engine # Core library (inference, engine, tools)
|
|
32
|
+
pip install entropic-engine[app] # TUI application (includes tui + storage deps)
|
|
33
|
+
pip install entropic-engine[voice] # Voice interface (PersonaPlex)
|
|
34
|
+
pip install entropic-engine[all] # Everything
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```
|
|
38
|
+
+-----------------------------------------------------+
|
|
39
|
+
| Application Layer (TUI / Headless / Custom) |
|
|
40
|
+
+-----------------------------------------------------+
|
|
41
|
+
| Engine | Orchestrator | Tools |
|
|
42
|
+
| - Agentic loop | - Tier routing | - Filesystem |
|
|
43
|
+
| - Directives | - Model swap | - Bash |
|
|
44
|
+
| - Compaction | - VRAM mgmt | - Diagnostics |
|
|
45
|
+
| - Context mgmt | - Adapters | - Git / Todo |
|
|
46
|
+
+-----------------------------------------------------+
|
|
47
|
+
| Inference Backend (llama-cpp-python) |
|
|
48
|
+
| - GGUF models, single-GPU, in-process |
|
|
49
|
+
+-----------------------------------------------------+
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Tier-Based Routing
|
|
53
|
+
|
|
54
|
+
A lightweight router model classifies each prompt and routes to the appropriate
|
|
55
|
+
tier. Only one main model is loaded at a time (VRAM constraint) — the
|
|
56
|
+
orchestrator handles dynamic swapping with lock-protected state transitions.
|
|
57
|
+
|
|
58
|
+
| Tier | Purpose | Typical Model |
|
|
59
|
+
|------|---------|---------------|
|
|
60
|
+
| **Thinking** | Complex reasoning, architecture, multi-step analysis | Qwen3-14B Q4_K_M |
|
|
61
|
+
| **Normal** | General conversation and tasks | Falcon-H1R-7B Q8_0 |
|
|
62
|
+
| **Code** | Code generation, editing, refactoring | Falcon-H1R-7B Q8_0 |
|
|
63
|
+
| **Simple** | Greetings, acknowledgments, short responses | (shares normal model) |
|
|
64
|
+
| **Router** | Prompt classification only | Qwen3-0.6B Q8_0 |
|
|
65
|
+
|
|
66
|
+
### Agentic Loop
|
|
67
|
+
|
|
68
|
+
The engine runs an autonomous tool-calling loop: generate -> parse tool calls ->
|
|
69
|
+
execute tools -> feed results back -> generate again. The loop continues until
|
|
70
|
+
the model produces a complete response or hits the iteration limit.
|
|
71
|
+
|
|
72
|
+
Tools communicate back to the engine via **directives** — structured signals
|
|
73
|
+
embedded in tool results that can trigger tier handoffs, context anchoring, and
|
|
74
|
+
state management without the model needing to orchestrate these concerns.
|
|
75
|
+
|
|
76
|
+
## Features
|
|
77
|
+
|
|
78
|
+
- **Fully Local** — All inference on your hardware via llama-cpp-python. No API keys.
|
|
79
|
+
- **Library API** — Embed the engine in your own application with `LibraryConfig`
|
|
80
|
+
- **Intelligent Routing** — Sub-second prompt classification routes to the right model tier
|
|
81
|
+
- **Single-GPU Orchestration** — Dynamic model swapping with VRAM-aware loading
|
|
82
|
+
- **Per-Model Adapters** — Model-specific chat templates, tool parsing, thinking block handling
|
|
83
|
+
- **Auto-Compaction** — Context summarization for long conversations
|
|
84
|
+
- **MCP Tools** — Filesystem, bash, diagnostics, git, and extensible tool servers
|
|
85
|
+
- **Headless Mode** — Full engine without TUI for automation and testing
|
|
86
|
+
- **TUI** — Terminal interface built on Textual with streaming, tool approval, voice input
|
|
87
|
+
|
|
88
|
+
## Requirements
|
|
89
|
+
|
|
90
|
+
- Linux (tested on Ubuntu 24.04)
|
|
91
|
+
- NVIDIA GPU with 16GB+ VRAM
|
|
92
|
+
- CUDA 12.4+
|
|
93
|
+
- Python 3.11+
|
|
94
|
+
|
|
95
|
+
## Quick Start
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
git clone https://github.com/tvanfossen/entropic.git
|
|
99
|
+
cd entropic
|
|
100
|
+
./install.sh app
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The install script creates a virtual environment, detects CUDA, and installs
|
|
104
|
+
with the `[app]` extras (TUI + storage dependencies).
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
# Place GGUF models in ~/models/gguf/ (or configure paths in .entropic/config.local.yaml)
|
|
108
|
+
|
|
109
|
+
# Run interactive TUI
|
|
110
|
+
.venv/bin/entropic
|
|
111
|
+
|
|
112
|
+
# Or headless
|
|
113
|
+
.venv/bin/entropic --headless
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## CLI
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
entropic # Interactive TUI
|
|
120
|
+
entropic --headless # Headless mode (automation/testing)
|
|
121
|
+
entropic status # Show model and system status
|
|
122
|
+
entropic ask "question" # Single-shot question
|
|
123
|
+
entropic init # Initialize .entropic/ in current directory
|
|
124
|
+
entropic download <model> # Download model files
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Configuration
|
|
128
|
+
|
|
129
|
+
Configuration loads in priority order (highest wins):
|
|
130
|
+
|
|
131
|
+
1. Built-in defaults
|
|
132
|
+
2. Global config (`~/.entropic/config.yaml`)
|
|
133
|
+
3. Project config (`.entropic/config.local.yaml`)
|
|
134
|
+
4. CLI arguments
|
|
135
|
+
|
|
136
|
+
Project context is provided via `.entropic/ENTROPIC.md` — a markdown file
|
|
137
|
+
describing the project that gets included in the system prompt.
|
|
138
|
+
|
|
139
|
+
## Library Usage
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
from entropic import LibraryConfig, Orchestrator, Engine, ServerManager
|
|
143
|
+
|
|
144
|
+
config = LibraryConfig(
|
|
145
|
+
config_dir=Path("~/.myapp").expanduser(),
|
|
146
|
+
tiers={"normal": {"path": "model.gguf", "adapter": "qwen3"}},
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
orchestrator = Orchestrator(config.to_app_config())
|
|
150
|
+
await orchestrator.initialize()
|
|
151
|
+
|
|
152
|
+
server_manager = ServerManager(config.to_app_config())
|
|
153
|
+
await server_manager.initialize()
|
|
154
|
+
|
|
155
|
+
engine = Engine(orchestrator=orchestrator, server_manager=server_manager)
|
|
156
|
+
async for message in engine.run("Hello"):
|
|
157
|
+
print(message.content)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
See `examples/hello-world/` and `examples/pychess/` for complete integrations.
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
Apache-2.0
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "entropic-engine"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Local-first agentic inference engine with tier-based model routing"
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = {text = "Apache-2.0"}
|
|
7
|
+
requires-python = ">=3.11"
|
|
8
|
+
authors = [
|
|
9
|
+
{name = "Tristan VanFossen"}
|
|
10
|
+
]
|
|
11
|
+
keywords = ["ai", "coding", "assistant", "llm", "local"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 3 - Alpha",
|
|
14
|
+
"Environment :: Console",
|
|
15
|
+
"Intended Audience :: Developers",
|
|
16
|
+
"License :: OSI Approved :: Apache Software License",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Topic :: Software Development",
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
dependencies = [
|
|
23
|
+
"llama-cpp-python>=0.2.0",
|
|
24
|
+
"mcp>=1.0.0",
|
|
25
|
+
"pydantic>=2.0.0",
|
|
26
|
+
"pydantic-settings>=2.0.0",
|
|
27
|
+
"pyyaml>=6.0.0",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
tui = [
|
|
32
|
+
"textual>=0.47.0",
|
|
33
|
+
"rich>=13.0.0",
|
|
34
|
+
"click>=8.0.0",
|
|
35
|
+
"pylspclient>=0.0.7",
|
|
36
|
+
]
|
|
37
|
+
app = [
|
|
38
|
+
"entropic-engine[tui]",
|
|
39
|
+
"aiosqlite>=0.19.0",
|
|
40
|
+
"httpx>=0.25.0",
|
|
41
|
+
]
|
|
42
|
+
all = ["entropic-engine[app,voice]"]
|
|
43
|
+
dev = [
|
|
44
|
+
"pytest>=7.0.0",
|
|
45
|
+
"pytest-asyncio>=0.21.0",
|
|
46
|
+
"pytest-bdd>=7.0.0",
|
|
47
|
+
"pytest-cov>=4.0.0",
|
|
48
|
+
"mypy>=1.0.0",
|
|
49
|
+
"black>=23.0.0",
|
|
50
|
+
"ruff>=0.1.0",
|
|
51
|
+
"pre-commit>=3.0.0",
|
|
52
|
+
"types-pyyaml>=6.0.0",
|
|
53
|
+
]
|
|
54
|
+
voice = [
|
|
55
|
+
# From PersonaPlex requirements
|
|
56
|
+
"numpy>=1.26,<2.2",
|
|
57
|
+
"safetensors>=0.4.0,<0.5",
|
|
58
|
+
"huggingface-hub>=0.24,<0.28",
|
|
59
|
+
"einops==0.7",
|
|
60
|
+
"sentencepiece==0.2",
|
|
61
|
+
"sounddevice==0.5",
|
|
62
|
+
"sphn>=0.1.4,<0.2",
|
|
63
|
+
"torch>=2.2.0",
|
|
64
|
+
"aiohttp>=3.10.5,<3.12",
|
|
65
|
+
"websockets>=12.0,<14.0",
|
|
66
|
+
# Optional for INT8 quantization
|
|
67
|
+
"accelerate>=0.30.0",
|
|
68
|
+
"torchao>=0.4.0",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
[project.scripts]
|
|
72
|
+
entropic = "entropic.cli:main"
|
|
73
|
+
entropic-voice-server = "entropic.voice.server:main"
|
|
74
|
+
|
|
75
|
+
[build-system]
|
|
76
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
77
|
+
build-backend = "setuptools.build_meta"
|
|
78
|
+
|
|
79
|
+
[tool.setuptools.packages.find]
|
|
80
|
+
where = ["src"]
|
|
81
|
+
|
|
82
|
+
[tool.setuptools.package-data]
|
|
83
|
+
entropic = ["data/*.yaml", "data/prompts/*.md", "data/grammars/*.gbnf", "data/tools/**/*.json", "ui/*.tcss"]
|
|
84
|
+
|
|
85
|
+
[tool.black]
|
|
86
|
+
line-length = 100
|
|
87
|
+
target-version = ["py311", "py312"]
|
|
88
|
+
|
|
89
|
+
[tool.ruff]
|
|
90
|
+
line-length = 100
|
|
91
|
+
extend-exclude = ["vendor"]
|
|
92
|
+
|
|
93
|
+
[tool.ruff.lint]
|
|
94
|
+
select = ["E", "F", "W", "I", "N", "UP", "B", "C4"]
|
|
95
|
+
ignore = ["E501"]
|
|
96
|
+
|
|
97
|
+
[tool.mypy]
|
|
98
|
+
python_version = "3.12"
|
|
99
|
+
strict = true
|
|
100
|
+
ignore_missing_imports = true
|
|
101
|
+
|
|
102
|
+
[[tool.mypy.overrides]]
|
|
103
|
+
module = "tests.*"
|
|
104
|
+
strict = false
|
|
105
|
+
disallow_untyped_defs = false
|
|
106
|
+
disallow_untyped_calls = false
|
|
107
|
+
disallow_incomplete_defs = false
|
|
108
|
+
|
|
109
|
+
[[tool.mypy.overrides]]
|
|
110
|
+
module = ["entropic.cli", "entropic.cli_download"]
|
|
111
|
+
disallow_untyped_decorators = false
|
|
112
|
+
|
|
113
|
+
[[tool.mypy.overrides]]
|
|
114
|
+
module = "entropic.mcp.servers.base"
|
|
115
|
+
disallow_untyped_decorators = false
|
|
116
|
+
|
|
117
|
+
[[tool.mypy.overrides]]
|
|
118
|
+
module = "entropic.ui.tui"
|
|
119
|
+
disallow_untyped_decorators = false
|
|
120
|
+
|
|
121
|
+
[tool.pytest.ini_options]
|
|
122
|
+
asyncio_mode = "auto"
|
|
123
|
+
testpaths = ["tests"]
|
|
124
|
+
python_files = ["test_*.py"]
|
|
125
|
+
python_functions = ["test_*"]
|
|
126
|
+
# Markers for categorizing tests
|
|
127
|
+
markers = [
|
|
128
|
+
"unit: Fast tests without external dependencies",
|
|
129
|
+
"integration: Tests requiring external services (docker, etc)",
|
|
130
|
+
"model: Tests requiring actual model inference (GPU recommended)",
|
|
131
|
+
"slow: Tests that take a long time to run",
|
|
132
|
+
]
|
|
133
|
+
# Run all tests by default including model tests
|
|
134
|
+
# Skip model tests with: pytest -m "not model"
|
|
135
|
+
# Run only model tests: pytest -m model
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Entropi - Local AI inference engine with multi-tier model orchestration.
|
|
3
|
+
|
|
4
|
+
Public API for library consumers. Install extras for additional features:
|
|
5
|
+
pip install entropic-engine # Core inference engine
|
|
6
|
+
pip install entropic-engine[tui] # Terminal UI application
|
|
7
|
+
pip install entropic-engine[voice] # Voice interface
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from entropic.config.loader import ConfigLoader, save_permission, validate_config
|
|
11
|
+
from entropic.config.schema import (
|
|
12
|
+
CompactionConfig,
|
|
13
|
+
EntropyConfig,
|
|
14
|
+
GenerationConfig,
|
|
15
|
+
LibraryConfig,
|
|
16
|
+
ModelConfig,
|
|
17
|
+
ModelsConfig,
|
|
18
|
+
RoutingConfig,
|
|
19
|
+
TierConfig,
|
|
20
|
+
)
|
|
21
|
+
from entropic.core.base import (
|
|
22
|
+
GenerationResult,
|
|
23
|
+
Message,
|
|
24
|
+
ModelBackend,
|
|
25
|
+
ModelTier,
|
|
26
|
+
ToolCall,
|
|
27
|
+
ToolProvider,
|
|
28
|
+
ToolResult,
|
|
29
|
+
)
|
|
30
|
+
from entropic.core.engine import AgentEngine, AgentState, EngineCallbacks, LoopConfig
|
|
31
|
+
from entropic.core.logging import setup_logging, setup_model_logger
|
|
32
|
+
from entropic.core.tool_validation import ToolValidationError
|
|
33
|
+
from entropic.inference.adapters import ChatAdapter, get_adapter, register_adapter
|
|
34
|
+
from entropic.inference.orchestrator import BackendFactory, ModelOrchestrator, RoutingResult
|
|
35
|
+
from entropic.mcp.manager import ServerManager
|
|
36
|
+
from entropic.mcp.provider import InProcessProvider
|
|
37
|
+
from entropic.mcp.servers.base import BaseMCPServer, ServerResponse, load_tool_definition
|
|
38
|
+
from entropic.mcp.tools import BaseTool, ToolRegistry
|
|
39
|
+
from entropic.prompts import TierIdentity, load_tier_identity
|
|
40
|
+
|
|
41
|
+
__version__ = "1.0.0"
|
|
42
|
+
__author__ = "Tristan VanFossen"
|
|
43
|
+
|
|
44
|
+
__all__ = [
|
|
45
|
+
# Core types
|
|
46
|
+
"GenerationResult",
|
|
47
|
+
"Message",
|
|
48
|
+
"ModelBackend",
|
|
49
|
+
"ModelTier",
|
|
50
|
+
"ToolCall",
|
|
51
|
+
"ToolProvider",
|
|
52
|
+
"ToolResult",
|
|
53
|
+
# Engine
|
|
54
|
+
"AgentEngine",
|
|
55
|
+
"AgentState",
|
|
56
|
+
"EngineCallbacks",
|
|
57
|
+
"LoopConfig",
|
|
58
|
+
# Logging
|
|
59
|
+
"setup_logging",
|
|
60
|
+
"setup_model_logger",
|
|
61
|
+
# Config
|
|
62
|
+
"ConfigLoader",
|
|
63
|
+
"save_permission",
|
|
64
|
+
"validate_config",
|
|
65
|
+
"CompactionConfig",
|
|
66
|
+
"EntropyConfig",
|
|
67
|
+
"GenerationConfig",
|
|
68
|
+
"LibraryConfig",
|
|
69
|
+
"ModelConfig",
|
|
70
|
+
"ModelsConfig",
|
|
71
|
+
"RoutingConfig",
|
|
72
|
+
"TierConfig",
|
|
73
|
+
# Orchestrator
|
|
74
|
+
"BackendFactory",
|
|
75
|
+
"ModelOrchestrator",
|
|
76
|
+
"RoutingResult",
|
|
77
|
+
# Adapters
|
|
78
|
+
"ChatAdapter",
|
|
79
|
+
"get_adapter",
|
|
80
|
+
"register_adapter",
|
|
81
|
+
# MCP
|
|
82
|
+
"BaseMCPServer",
|
|
83
|
+
"BaseTool",
|
|
84
|
+
"InProcessProvider",
|
|
85
|
+
"ServerManager",
|
|
86
|
+
"ServerResponse",
|
|
87
|
+
"ToolRegistry",
|
|
88
|
+
"ToolValidationError",
|
|
89
|
+
"load_tool_definition",
|
|
90
|
+
# Prompts
|
|
91
|
+
"TierIdentity",
|
|
92
|
+
"load_tier_identity",
|
|
93
|
+
]
|