zenthrix 0.1.3__tar.gz → 0.2.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.
Files changed (40) hide show
  1. {zenthrix-0.1.3 → zenthrix-0.2.0}/CHANGELOG.md +17 -0
  2. {zenthrix-0.1.3 → zenthrix-0.2.0}/PKG-INFO +12 -4
  3. {zenthrix-0.1.3 → zenthrix-0.2.0}/README.md +10 -3
  4. {zenthrix-0.1.3 → zenthrix-0.2.0}/pyproject.toml +4 -2
  5. {zenthrix-0.1.3 → zenthrix-0.2.0}/python/zenthrix/__init__.py +4 -1
  6. {zenthrix-0.1.3 → zenthrix-0.2.0}/python/zenthrix/adapters/__init__.py +7 -1
  7. zenthrix-0.2.0/python/zenthrix/adapters/safetensors_loader.py +16 -0
  8. zenthrix-0.2.0/python/zenthrix/cli.py +227 -0
  9. zenthrix-0.2.0/python/zenthrix/metadata.py +342 -0
  10. zenthrix-0.2.0/python/zenthrix/runtime.py +96 -0
  11. zenthrix-0.2.0/python/zenthrix/settings.py +103 -0
  12. {zenthrix-0.1.3 → zenthrix-0.2.0}/python/zenthrix/validation.py +3 -1
  13. {zenthrix-0.1.3 → zenthrix-0.2.0}/tests/test_cli.py +34 -5
  14. zenthrix-0.2.0/tests/test_metadata.py +185 -0
  15. zenthrix-0.2.0/tests/test_runtime.py +92 -0
  16. zenthrix-0.2.0/tests/test_settings.py +99 -0
  17. {zenthrix-0.1.3 → zenthrix-0.2.0}/tests/test_validation.py +25 -1
  18. zenthrix-0.1.3/python/zenthrix/cli.py +0 -110
  19. zenthrix-0.1.3/python/zenthrix/runtime.py +0 -53
  20. {zenthrix-0.1.3 → zenthrix-0.2.0}/.github/CODEOWNERS +0 -0
  21. {zenthrix-0.1.3 → zenthrix-0.2.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  22. {zenthrix-0.1.3 → zenthrix-0.2.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
  23. {zenthrix-0.1.3 → zenthrix-0.2.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  24. {zenthrix-0.1.3 → zenthrix-0.2.0}/.github/SECURITY.md +0 -0
  25. {zenthrix-0.1.3 → zenthrix-0.2.0}/.github/SUPPORT.md +0 -0
  26. {zenthrix-0.1.3 → zenthrix-0.2.0}/.github/dependabot.yml +0 -0
  27. {zenthrix-0.1.3 → zenthrix-0.2.0}/.github/pull_request_template.md +0 -0
  28. {zenthrix-0.1.3 → zenthrix-0.2.0}/.github/workflows/ci.yml +0 -0
  29. {zenthrix-0.1.3 → zenthrix-0.2.0}/.github/workflows/release.yml +0 -0
  30. {zenthrix-0.1.3 → zenthrix-0.2.0}/.gitignore +0 -0
  31. {zenthrix-0.1.3 → zenthrix-0.2.0}/CONTRIBUTING.md +0 -0
  32. {zenthrix-0.1.3 → zenthrix-0.2.0}/LICENSE +0 -0
  33. {zenthrix-0.1.3 → zenthrix-0.2.0}/python/zenthrix/adapters/gguf_loader.py +0 -0
  34. {zenthrix-0.1.3 → zenthrix-0.2.0}/python/zenthrix/adapters/onnx_loader.py +0 -0
  35. {zenthrix-0.1.3 → zenthrix-0.2.0}/python/zenthrix/adapters/pytorch_loader.py +0 -0
  36. {zenthrix-0.1.3 → zenthrix-0.2.0}/python/zenthrix/config.py +0 -0
  37. {zenthrix-0.1.3 → zenthrix-0.2.0}/python/zenthrix/engine.py +0 -0
  38. {zenthrix-0.1.3 → zenthrix-0.2.0}/python/zenthrix/exceptions.py +0 -0
  39. {zenthrix-0.1.3 → zenthrix-0.2.0}/tests/test_engine.py +0 -0
  40. {zenthrix-0.1.3 → zenthrix-0.2.0}/uv.lock +0 -0
@@ -5,6 +5,22 @@ All notable changes to Zenthrix are documented here.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project follows [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [0.2.0] - 2026-09-23
9
+
10
+ ### Added
11
+
12
+ - **SafeTensors format support**: Added `.safetensors` model input format adapter alongside ONNX, GGUF, and PyTorch.
13
+ - **Model metadata inspection**: Extract tensor names, shapes, dtypes, parameter counts, and estimated memory footprint directly from SafeTensors, GGUF, and ONNX source model files without requiring the native engine or loading full weights into RAM.
14
+ - **Configuration file support (`zenthrix.toml`)**: Added project-level defaults for compilation (`target`, `quantization`, `output`) and inference (`max_tokens`, `temperature`) resolved hierarchically with CLI override precedence.
15
+ - **Runtime plugin discovery**: Dynamic discovery of third-party or native runtime adapters registered through the `zenthrix.runtimes` entry point group.
16
+ - **`zenthrix plugins` CLI command**: Inspect and list all discovered runtime plugins in the current Python environment.
17
+ - Exported `ModelMetadata` and `TensorInfo` in the public API.
18
+
19
+ ### Changed
20
+
21
+ - Bumped the package and public API version to `0.2.0`.
22
+ - Added conditional dependency on `tomli` for Python < 3.11.
23
+
8
24
  ## [0.1.3] - 2026-09-18
9
25
 
10
26
  ### Changed
@@ -66,3 +82,4 @@ and this project follows [Semantic Versioning](https://semver.org/).
66
82
  [0.1.1]: https://github.com/withbrian-technologies/zenthrix/releases/tag/v0.1.1
67
83
  [0.1.2]: https://github.com/withbrian-technologies/zenthrix/releases/tag/v0.1.2
68
84
  [0.1.3]: https://github.com/withbrian-technologies/zenthrix/releases/tag/v0.1.3
85
+ [0.2.0]: https://github.com/withbrian-technologies/zenthrix/releases/tag/v0.2.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: zenthrix
3
- Version: 0.1.3
3
+ Version: 0.2.0
4
4
  Summary: Hardware-adaptive edge neural graph compiler frontend
5
5
  Author: WithBrian Technologies
6
6
  License: Apache License
@@ -210,6 +210,7 @@ Classifier: License :: OSI Approved :: Apache Software License
210
210
  Classifier: Programming Language :: Python :: 3
211
211
  Classifier: Programming Language :: Python :: 3 :: Only
212
212
  Requires-Python: >=3.10
213
+ Requires-Dist: tomli>=2.0; python_version < '3.11'
213
214
  Description-Content-Type: text/markdown
214
215
 
215
216
  # Zenthrix
@@ -239,7 +240,7 @@ Zenthrix is an edge-native model compiler frontend for compiling open-weight neu
239
240
 
240
241
  ## Key Features
241
242
 
242
- - **Direct Ingestion** — Native loaders for ONNX, PyTorch Export (AOTInductor), and GGUF architectures, with no intermediate format conversion required.
243
+ - **Direct Ingestion** — Native loaders for SafeTensors, ONNX, PyTorch Export (AOTInductor), and GGUF architectures, with no intermediate format conversion required.
243
244
  - **Unified Memory Tiling** — Schedules compute passes against unified memory architectures, reducing peak active RAM allocation by up to 40%.
244
245
  - **Zero-Copy Runtime** — Emits standalone, relocatable `.zx` binaries that execute locally without a heavy Python runtime dependency.
245
246
  - **Privacy-First Compilation** — Models compile entirely on-device; weights and computational graphs never leave the local environment.
@@ -291,9 +292,16 @@ zenthrix compile \
291
292
  --output ./llama-3.2-1b.zx
292
293
  ```
293
294
 
294
- ### 2. Inspect Graph Optimizations
295
+ ### 2. Inspect Models & Graph Optimizations
295
296
 
296
- Analyze operator fusions and projected memory footprints prior to compilation:
297
+ Inspect uncompiled source models (`.safetensors`, `.gguf`, `.onnx`) directly to view parameter counts, tensor shapes, and estimated memory footprint without requiring the native engine:
298
+
299
+ ```bash
300
+ zenthrix inspect ./model.safetensors
301
+ zenthrix inspect ./model.gguf --json
302
+ ```
303
+
304
+ For compiled `.zx` binaries, inspect projected memory profiles and operator fusions:
297
305
 
298
306
  ```bash
299
307
  zenthrix inspect ./llama-3.2-1b.zx --memory-profile
@@ -25,7 +25,7 @@ Zenthrix is an edge-native model compiler frontend for compiling open-weight neu
25
25
 
26
26
  ## Key Features
27
27
 
28
- - **Direct Ingestion** — Native loaders for ONNX, PyTorch Export (AOTInductor), and GGUF architectures, with no intermediate format conversion required.
28
+ - **Direct Ingestion** — Native loaders for SafeTensors, ONNX, PyTorch Export (AOTInductor), and GGUF architectures, with no intermediate format conversion required.
29
29
  - **Unified Memory Tiling** — Schedules compute passes against unified memory architectures, reducing peak active RAM allocation by up to 40%.
30
30
  - **Zero-Copy Runtime** — Emits standalone, relocatable `.zx` binaries that execute locally without a heavy Python runtime dependency.
31
31
  - **Privacy-First Compilation** — Models compile entirely on-device; weights and computational graphs never leave the local environment.
@@ -77,9 +77,16 @@ zenthrix compile \
77
77
  --output ./llama-3.2-1b.zx
78
78
  ```
79
79
 
80
- ### 2. Inspect Graph Optimizations
80
+ ### 2. Inspect Models & Graph Optimizations
81
81
 
82
- Analyze operator fusions and projected memory footprints prior to compilation:
82
+ Inspect uncompiled source models (`.safetensors`, `.gguf`, `.onnx`) directly to view parameter counts, tensor shapes, and estimated memory footprint without requiring the native engine:
83
+
84
+ ```bash
85
+ zenthrix inspect ./model.safetensors
86
+ zenthrix inspect ./model.gguf --json
87
+ ```
88
+
89
+ For compiled `.zx` binaries, inspect projected memory profiles and operator fusions:
83
90
 
84
91
  ```bash
85
92
  zenthrix inspect ./llama-3.2-1b.zx --memory-profile
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "zenthrix"
7
- version = "0.1.3"
7
+ version = "0.2.0"
8
8
  description = "Hardware-adaptive edge neural graph compiler frontend"
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -16,7 +16,9 @@ classifiers = [
16
16
  "Programming Language :: Python :: 3",
17
17
  "Programming Language :: Python :: 3 :: Only",
18
18
  ]
19
- dependencies = []
19
+ dependencies = [
20
+ "tomli>=2.0; python_version < '3.11'",
21
+ ]
20
22
 
21
23
  [dependency-groups]
22
24
  dev = [
@@ -2,14 +2,17 @@
2
2
 
3
3
  from .engine import Engine, InferenceResult
4
4
  from .exceptions import EngineUnavailableError, InputValidationError, ZenthrixError
5
+ from .metadata import ModelMetadata, TensorInfo
5
6
 
6
- __version__ = "0.1.3"
7
+ __version__ = "0.2.0"
7
8
 
8
9
  __all__ = [
9
10
  "Engine",
10
11
  "EngineUnavailableError",
11
12
  "InferenceResult",
12
13
  "InputValidationError",
14
+ "ModelMetadata",
15
+ "TensorInfo",
13
16
  "ZenthrixError",
14
17
  "__version__",
15
18
  ]
@@ -3,6 +3,12 @@
3
3
  from .gguf_loader import validate_gguf
4
4
  from .onnx_loader import validate_onnx
5
5
  from .pytorch_loader import validate_pytorch_export
6
+ from .safetensors_loader import validate_safetensors
6
7
 
7
- __all__ = ["validate_gguf", "validate_onnx", "validate_pytorch_export"]
8
+ __all__ = [
9
+ "validate_gguf",
10
+ "validate_onnx",
11
+ "validate_pytorch_export",
12
+ "validate_safetensors",
13
+ ]
8
14
 
@@ -0,0 +1,16 @@
1
+ """SafeTensors input validation."""
2
+
3
+ from pathlib import Path
4
+
5
+ from ..exceptions import InputValidationError
6
+ from ..validation import validate_model_path
7
+
8
+
9
+ def validate_safetensors(path: str | Path) -> Path:
10
+ """Validate a SafeTensors model path."""
11
+ model_path = validate_model_path(path)
12
+ if model_path.suffix.lower() != ".safetensors":
13
+ raise InputValidationError(
14
+ f"Expected a .safetensors file, got: {model_path}"
15
+ )
16
+ return model_path
@@ -0,0 +1,227 @@
1
+ """Command-line interface for the Zenthrix frontend."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import json
7
+ import sys
8
+ from typing import TYPE_CHECKING
9
+
10
+ if TYPE_CHECKING:
11
+ from .metadata import ModelMetadata
12
+
13
+ from . import __version__
14
+ from .engine import Engine
15
+ from .exceptions import EngineUnavailableError, ZenthrixError
16
+ from .validation import (
17
+ validate_compile_options,
18
+ validate_compiled_model_path,
19
+ validate_model_input,
20
+ )
21
+
22
+
23
+ def build_parser() -> argparse.ArgumentParser:
24
+ """Build the command-line parser."""
25
+ parser = argparse.ArgumentParser(prog="zenthrix")
26
+ parser.add_argument("--version", action="version", version=__version__)
27
+ commands = parser.add_subparsers(dest="command", required=True)
28
+
29
+ compile_parser = commands.add_parser("compile", help="Compile a model")
30
+ compile_parser.add_argument("--model", required=True)
31
+ compile_parser.add_argument("--format", required=True, dest="model_format")
32
+ compile_parser.add_argument("--target", default="auto")
33
+ compile_parser.add_argument("--quantization", default=None)
34
+ compile_parser.add_argument("--output", required=True)
35
+ compile_parser.add_argument("--json", action="store_true")
36
+
37
+ inspect_parser = commands.add_parser(
38
+ "inspect", help="Inspect a compiled or source model"
39
+ )
40
+ inspect_parser.add_argument("model")
41
+ inspect_parser.add_argument("--memory-profile", action="store_true")
42
+ inspect_parser.add_argument("--json", action="store_true")
43
+
44
+ run_parser = commands.add_parser("run", help="Run inference")
45
+ run_parser.add_argument("--model", required=True)
46
+ run_parser.add_argument("--prompt", required=True)
47
+ run_parser.add_argument("--max-tokens", type=int, default=None)
48
+ run_parser.add_argument("--temperature", type=float, default=None)
49
+ run_parser.add_argument("--json", action="store_true")
50
+
51
+ commands.add_parser("plugins", help="List installed runtime plugins")
52
+
53
+ return parser
54
+
55
+
56
+ def _compile(args: argparse.Namespace) -> int:
57
+ validate_model_input(args.model, args.model_format)
58
+ validate_compile_options(args.target, args.quantization, args.output)
59
+ raise ZenthrixError(
60
+ "The native compiler engine is not installed. "
61
+ "The public frontend cannot produce a .zx binary yet."
62
+ )
63
+
64
+
65
+ def _inspect(args: argparse.Namespace) -> int:
66
+ # Source model inspection — works without native engine
67
+ model_path = args.model
68
+ suffix = model_path.rsplit(".", 1)[-1].lower() if "." in model_path else ""
69
+
70
+ if suffix == "zx":
71
+ validate_compiled_model_path(model_path)
72
+ raise EngineUnavailableError(
73
+ "The Zenthrix native engine is not installed. "
74
+ "Install the platform runtime before inspecting compiled models."
75
+ )
76
+
77
+ # Inspect a source model (safetensors, gguf, onnx)
78
+ from .metadata import extract_metadata
79
+
80
+ meta = extract_metadata(model_path)
81
+
82
+ if args.json:
83
+ print(json.dumps(meta.to_dict()))
84
+ else:
85
+ _print_metadata(meta)
86
+ return 0
87
+
88
+
89
+ def _print_metadata(meta: ModelMetadata) -> None:
90
+ """Pretty-print model metadata to stdout."""
91
+
92
+ lines = [
93
+ "",
94
+ f" Model: {meta.path}",
95
+ f" Format: {meta.format}",
96
+ f" File size: {_format_size(meta.file_size_bytes)}",
97
+ ]
98
+ if meta.parameter_count:
99
+ lines.append(f" Parameters: {meta.parameter_count:,}")
100
+ if meta.estimated_memory_mb:
101
+ lines.append(f" Est. memory: {meta.estimated_memory_mb:.1f} MB")
102
+ if meta.architecture:
103
+ lines.append(f" Architecture: {meta.architecture}")
104
+ if meta.tensors:
105
+ lines.append(f" Tensors: {len(meta.tensors)}")
106
+ if meta.extra:
107
+ for key, value in sorted(meta.extra.items()):
108
+ lines.append(f" {key}: {value}")
109
+ lines.append("")
110
+ print("\n".join(lines))
111
+
112
+
113
+ def _format_size(size_bytes: int) -> str:
114
+ """Format byte count as a human-readable string."""
115
+ if size_bytes >= 1_073_741_824:
116
+ return f"{size_bytes / 1_073_741_824:.1f} GB"
117
+ if size_bytes >= 1_048_576:
118
+ return f"{size_bytes / 1_048_576:.1f} MB"
119
+ if size_bytes >= 1024:
120
+ return f"{size_bytes / 1024:.1f} KB"
121
+ return f"{size_bytes} B"
122
+
123
+
124
+ def _run(args: argparse.Namespace) -> int:
125
+ result = Engine(args.model).generate(
126
+ args.prompt,
127
+ temperature=args.temperature if args.temperature is not None else 0.2,
128
+ max_tokens=args.max_tokens if args.max_tokens is not None else 128,
129
+ )
130
+ if args.json:
131
+ print(
132
+ json.dumps(
133
+ {
134
+ "text": result.text,
135
+ "ttft_ms": result.ttft_ms,
136
+ "tokens_per_second": result.tokens_per_second,
137
+ }
138
+ )
139
+ )
140
+ else:
141
+ print(result.text)
142
+ return 0
143
+
144
+
145
+ def _plugins(_args: argparse.Namespace) -> int:
146
+ from .runtime import discover_runtimes
147
+
148
+ runtimes = discover_runtimes()
149
+ if not runtimes:
150
+ print("No runtime plugins installed.")
151
+ print()
152
+ print("Install a compatible runtime package, or see:")
153
+ print(" https://github.com/withbrian-technologies/zenthrix#plugins")
154
+ return 0
155
+
156
+ print("Installed runtimes:")
157
+ for name, adapter_cls in runtimes:
158
+ module = f"{adapter_cls.__module__}:{adapter_cls.__qualname__}"
159
+ print(f" • {name} ({module})")
160
+ return 0
161
+
162
+
163
+ def main(argv: list[str] | None = None) -> int:
164
+ """Run the CLI and return a process exit code."""
165
+ args = build_parser().parse_args(argv)
166
+
167
+ # Merge config-file defaults for compile/run when available
168
+ _apply_config_defaults(args)
169
+
170
+ try:
171
+ if args.command == "compile":
172
+ return _compile(args)
173
+ if args.command == "inspect":
174
+ return _inspect(args)
175
+ if args.command == "run":
176
+ return _run(args)
177
+ if args.command == "plugins":
178
+ return _plugins(args)
179
+ except (ZenthrixError, ValueError) as error:
180
+ if getattr(args, "json", False):
181
+ print(
182
+ json.dumps(
183
+ {
184
+ "error": type(error).__name__,
185
+ "message": str(error),
186
+ }
187
+ )
188
+ )
189
+ else:
190
+ print(f"zenthrix: error: {error}", file=sys.stderr)
191
+ return 2
192
+ return 0
193
+
194
+
195
+ def _apply_config_defaults(args: argparse.Namespace) -> None:
196
+ """Load zenthrix.toml and fill in missing CLI arguments."""
197
+ try:
198
+ from .settings import find_config, load_config
199
+ except ImportError:
200
+ return
201
+
202
+ config_path = find_config()
203
+ if config_path is None:
204
+ return
205
+
206
+ try:
207
+ config = load_config(config_path)
208
+ except Exception:
209
+ return # silently skip broken config during CLI execution
210
+
211
+ command = getattr(args, "command", None)
212
+ section = config.get(command, {}) if command else {}
213
+ if not isinstance(section, dict):
214
+ return
215
+
216
+ for key, value in section.items():
217
+ # CLI arguments take precedence — only fill in None values
218
+ current = getattr(args, key, _SENTINEL)
219
+ if current is None:
220
+ setattr(args, key, value)
221
+
222
+
223
+ _SENTINEL = object()
224
+
225
+
226
+ if __name__ == "__main__":
227
+ raise SystemExit(main())